Merge "Fix coordinate error after rotation and scaling in TouchInputMapper"
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index 3dd1534..49a616f 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -57,13 +57,15 @@
struct AAsset;
-#if __ANDROID_API__ >= 30
-
/**
- * {@link AImageDecoder} functions result code. Many functions will return one of these
- * to indicate success ({@link ANDROID_IMAGE_DECODER_SUCCESS}) or the reason
- * for the failure. On failure, any out-parameters should be considered
- * uninitialized, except where specified.
+ * {@link AImageDecoder} functions result code.
+ *
+ * Introduced in API 30.
+ *
+ * Many functions will return this to indicate success
+ * ({@link ANDROID_IMAGE_DECODER_SUCCESS}) or the reason for the failure. On
+ * failure, any out-parameters should be considered uninitialized, except where
+ * specified.
*/
enum {
/**
@@ -115,6 +117,8 @@
/**
* Opaque handle for decoding images.
*
+ * Introduced in API 30
+ *
* Create using one of the following:
* - {@link AImageDecoder_createFromAAsset}
* - {@link AImageDecoder_createFromFd}
@@ -130,6 +134,8 @@
*/
typedef struct AImageDecoder AImageDecoder;
+#if __ANDROID_API__ >= 30
+
/**
* Create a new {@link AImageDecoder} from an {@link AAsset}.
*
@@ -331,7 +337,6 @@
int AImageDecoder_setTargetSize(AImageDecoder* _Nonnull decoder, int32_t width,
int32_t height) __INTRODUCED_IN(30);
-
/**
* Compute the dimensions to use for a given sampleSize.
*
@@ -361,6 +366,7 @@
int AImageDecoder_computeSampledSize(const AImageDecoder* _Nonnull decoder, int sampleSize,
int32_t* _Nonnull width, int32_t* _Nonnull height)
__INTRODUCED_IN(30);
+
/**
* Specify how to crop the output after scaling (if any).
*
@@ -388,15 +394,22 @@
*/
int AImageDecoder_setCrop(AImageDecoder* _Nonnull decoder, ARect crop) __INTRODUCED_IN(30);
+#endif // __ANDROID_API__ >= 30
+
struct AImageDecoderHeaderInfo;
/**
- * Opaque handle for representing information about the encoded image. Retrieved
- * using {@link AImageDecoder_getHeaderInfo} and passed to methods like
- * {@link AImageDecoderHeaderInfo_getWidth} and
+ * Opaque handle for representing information about the encoded image.
+ *
+ * Introduced in API 30
+ *
+ * Retrieved using {@link AImageDecoder_getHeaderInfo} and passed to methods
+ * like {@link AImageDecoderHeaderInfo_getWidth} and
* {@link AImageDecoderHeaderInfo_getHeight}.
*/
typedef struct AImageDecoderHeaderInfo AImageDecoderHeaderInfo;
+#if __ANDROID_API__ >= 30
+
/**
* Return an opaque handle for reading header info.
*
@@ -557,14 +570,20 @@
bool AImageDecoder_isAnimated(AImageDecoder* _Nonnull decoder)
__INTRODUCED_IN(31);
+#endif // __ANDROID_API__ >= 31
+
enum {
/*
* Reported by {@link AImageDecoder_getRepeatCount} if the
* animation should repeat forever.
+ *
+ * Introduced in API 31
*/
ANDROID_IMAGE_DECODER_INFINITE = INT32_MAX,
};
+#if __ANDROID_API__ >= 31
+
/**
* Report how many times the animation should repeat.
*
diff --git a/include/android/thermal.h b/include/android/thermal.h
index 83582d6..eb81534 100644
--- a/include/android/thermal.h
+++ b/include/android/thermal.h
@@ -53,7 +53,7 @@
#include <sys/types.h>
#if !defined(__INTRODUCED_IN)
-#define __INTRODUCED_IN(30) /* Introduced in API level 30 */
+#define __INTRODUCED_IN(__api_level) /* nothing */
#endif
#ifdef __cplusplus
@@ -181,6 +181,51 @@
#endif // __ANDROID_API__ >= 30
+#if __ANDROID_API__ >= 31
+
+/**
+ * Provides an estimate of how much thermal headroom the device currently has before
+ * hitting severe throttling.
+ *
+ * Note that this only attempts to track the headroom of slow-moving sensors, such as
+ * the skin temperature sensor. This means that there is no benefit to calling this function
+ * more frequently than about once per second, and attempted to call significantly
+ * more frequently may result in the function returning {@code NaN}.
+ *
+ * In addition, in order to be able to provide an accurate forecast, the system does
+ * not attempt to forecast until it has multiple temperature samples from which to
+ * extrapolate. This should only take a few seconds from the time of the first call,
+ * but during this time, no forecasting will occur, and the current headroom will be
+ * returned regardless of the value of {@code forecastSeconds}.
+ *
+ * The value returned is a non-negative float that represents how much of the thermal envelope
+ * is in use (or is forecasted to be in use). A value of 1.0 indicates that the device is
+ * (or will be) throttled at {@link #THERMAL_STATUS_SEVERE}. Such throttling can affect the
+ * CPU, GPU, and other subsystems. Values may exceed 1.0, but there is no implied mapping
+ * to specific thermal levels beyond that point. This means that values greater than 1.0
+ * may correspond to {@link #THERMAL_STATUS_SEVERE}, but may also represent heavier throttling.
+ *
+ * A value of 0.0 corresponds to a fixed distance from 1.0, but does not correspond to any
+ * particular thermal status or temperature. Values on (0.0, 1.0] may be expected to scale
+ * linearly with temperature, though temperature changes over time are typically not linear.
+ * Negative values will be clamped to 0.0 before returning.
+ *
+ * Available since API level 31.
+ *
+ * @param manager The manager instance to use.
+ * Acquired via {@link AThermal_acquireManager}.
+ * @param forecastSeconds how many seconds into the future to forecast. Given that device
+ * conditions may change at any time, forecasts from further in the
+ * future will likely be less accurate than forecasts in the near future.
+ * @return a value greater than equal to 0.0, where 1.0 indicates the SEVERE throttling threshold,
+ * as described above. Returns NaN if the device does not support this functionality or
+ * if this function is called significantly faster than once per second.
+ */
+float AThermal_getThermalHeadroom(AThermalManager *manager,
+ int forecastSeconds) __INTRODUCED_IN(31);
+
+#endif // __ANDROID_API__ >= 31
+
#ifdef __cplusplus
}
#endif
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index 639df7a..4aa2f60 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -37,6 +37,7 @@
PLAYER_STATE_STARTED = 2,
PLAYER_STATE_PAUSED = 3,
PLAYER_STATE_STOPPED = 4,
+ PLAYER_UPDATE_DEVICE_ID = 5,
} player_state_t;
// must be kept in sync with definitions in AudioManager.java
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index 2f5ccb8..7d1f38f 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -49,7 +49,8 @@
audio_content_type_t content, const sp<IBinder>& player) = 0;
/*oneway*/ virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,
audio_content_type_t content)= 0;
- /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event) = 0;
+ /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
+ audio_port_handle_t deviceId) = 0;
/*oneway*/ virtual status_t releasePlayer(audio_unique_id_t piid) = 0;
virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) = 0;
/*oneway*/ virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) = 0;
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index dae6eeb..15bd5c3 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -282,9 +282,8 @@
LOG(FATAL) << "adbd_auth: unhandled packet type?";
}
- output_queue_.pop_front();
-
ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
+ output_queue_.pop_front();
if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
PLOG(ERROR) << "adbd_auth: failed to write to framework fd";
ReplaceFrameworkFd(unique_fd());
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index 2e15e50..1173138 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "log/log_main.h"
#define LOG_TAG "AidlLazyServiceRegistrar"
#include <binder/LazyServiceRegistrar.h>
@@ -37,6 +38,13 @@
bool allowIsolated, int dumpFlags);
void forcePersist(bool persist);
+ void setActiveServicesCountCallback(const std::function<bool(int)>&
+ activeServicesCountCallback);
+
+ bool tryUnregister();
+
+ void reRegister();
+
protected:
Status onClients(const sp<IBinder>& service, bool clients) override;
@@ -49,6 +57,7 @@
// whether, based on onClients calls, we know we have a client for this
// service or not
bool clients = false;
+ bool registered = true;
};
/**
@@ -62,6 +71,14 @@
*/
void tryShutdown();
+ /**
+ * Try to shutdown the process, unless:
+ * - 'forcePersist' is 'true', or
+ * - The active services count callback returns 'true', or
+ * - Some services have clients.
+ */
+ void maybeTryShutdown();
+
// count of services with clients
size_t mNumConnectedServices;
@@ -69,6 +86,9 @@
std::map<std::string, Service> mRegisteredServices;
bool mForcePersist;
+
+ // Callback used to report the number of services with clients
+ std::function<bool(int)> mActiveServicesCountCallback;
};
class ClientCounterCallback {
@@ -83,6 +103,13 @@
*/
void forcePersist(bool persist);
+ void setActiveServicesCountCallback(const std::function<bool(int)>&
+ activeServicesCountCallback);
+
+ bool tryUnregister();
+
+ void reRegister();
+
private:
sp<ClientCounterCallbackImpl> mImpl;
};
@@ -131,8 +158,60 @@
void ClientCounterCallbackImpl::forcePersist(bool persist) {
mForcePersist = persist;
- if(!mForcePersist) {
+ if (!mForcePersist && mNumConnectedServices == 0) {
// Attempt a shutdown in case the number of clients hit 0 while the flag was on
+ maybeTryShutdown();
+ }
+}
+
+bool ClientCounterCallbackImpl::tryUnregister() {
+ auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
+
+ for (auto& [name, entry] : mRegisteredServices) {
+ bool success = manager->tryUnregisterService(name, entry.service).isOk();
+
+ if (!success) {
+ ALOGI("Failed to unregister service %s", name.c_str());
+ return false;
+ }
+ entry.registered = false;
+ }
+
+ return true;
+}
+
+void ClientCounterCallbackImpl::reRegister() {
+ for (auto& [name, entry] : mRegisteredServices) {
+ // re-register entry if not already registered
+ if (entry.registered) {
+ continue;
+ }
+
+ if (!registerService(entry.service, name, entry.allowIsolated,
+ entry.dumpFlags)) {
+ // Must restart. Otherwise, clients will never be able to get a hold of this service.
+ LOG_ALWAYS_FATAL("Bad state: could not re-register services");
+ }
+
+ entry.registered = true;
+ }
+}
+
+void ClientCounterCallbackImpl::maybeTryShutdown() {
+ if (mForcePersist) {
+ ALOGI("Shutdown prevented by forcePersist override flag.");
+ return;
+ }
+
+ bool handledInCallback = false;
+ if (mActiveServicesCountCallback != nullptr) {
+ handledInCallback = mActiveServicesCountCallback(mNumConnectedServices);
+ }
+
+ // If there is no callback defined or the callback did not handle this
+ // client count change event, try to shutdown the process if its services
+ // have no clients.
+ if (!handledInCallback && mNumConnectedServices == 0) {
tryShutdown();
}
}
@@ -162,53 +241,24 @@
ALOGI("Process has %zu (of %zu available) client(s) in use after notification %s has clients: %d",
mNumConnectedServices, mRegisteredServices.size(), name.c_str(), clients);
- tryShutdown();
+ maybeTryShutdown();
return Status::ok();
}
-void ClientCounterCallbackImpl::tryShutdown() {
- if(mNumConnectedServices > 0) {
- // Should only shut down if there are no clients
- return;
- }
+ void ClientCounterCallbackImpl::tryShutdown() {
+ ALOGI("Trying to shut down the service. No clients in use for any service in process.");
- if(mForcePersist) {
- ALOGI("Shutdown prevented by forcePersist override flag.");
- return;
- }
+ if (tryUnregister()) {
+ ALOGI("Unregistered all clients and exiting");
+ exit(EXIT_SUCCESS);
+ }
- ALOGI("Trying to shut down the service. No clients in use for any service in process.");
+ reRegister();
+}
- auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
-
- auto unRegisterIt = mRegisteredServices.begin();
- for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) {
- auto& entry = (*unRegisterIt);
-
- bool success = manager->tryUnregisterService(entry.first, entry.second.service).isOk();
-
- if (!success) {
- ALOGI("Failed to unregister service %s", entry.first.c_str());
- break;
- }
- }
-
- if (unRegisterIt == mRegisteredServices.end()) {
- ALOGI("Unregistered all clients and exiting");
- exit(EXIT_SUCCESS);
- }
-
- for (auto reRegisterIt = mRegisteredServices.begin(); reRegisterIt != unRegisterIt;
- reRegisterIt++) {
- auto& entry = (*reRegisterIt);
-
- // re-register entry
- if (!registerService(entry.second.service, entry.first, entry.second.allowIsolated,
- entry.second.dumpFlags)) {
- // Must restart. Otherwise, clients will never be able to get a hold of this service.
- ALOGE("Bad state: could not re-register services");
- }
- }
+void ClientCounterCallbackImpl::setActiveServicesCountCallback(const std::function<bool(int)>&
+ activeServicesCountCallback) {
+ mActiveServicesCountCallback = activeServicesCountCallback;
}
ClientCounterCallback::ClientCounterCallback() {
@@ -224,6 +274,19 @@
mImpl->forcePersist(persist);
}
+void ClientCounterCallback::setActiveServicesCountCallback(const std::function<bool(int)>&
+ activeServicesCountCallback) {
+ mImpl->setActiveServicesCountCallback(activeServicesCountCallback);
+}
+
+bool ClientCounterCallback::tryUnregister() {
+ return mImpl->tryUnregister();
+}
+
+void ClientCounterCallback::reRegister() {
+ mImpl->reRegister();
+}
+
} // namespace internal
LazyServiceRegistrar::LazyServiceRegistrar() {
@@ -247,5 +310,18 @@
mClientCC->forcePersist(persist);
}
+void LazyServiceRegistrar::setActiveServicesCountCallback(const std::function<bool(int)>&
+ activeServicesCountCallback) {
+ mClientCC->setActiveServicesCountCallback(activeServicesCountCallback);
+}
+
+bool LazyServiceRegistrar::tryUnregister() {
+ return mClientCC->tryUnregister();
+}
+
+void LazyServiceRegistrar::reRegister() {
+ mClientCC->reRegister();
+}
+
} // namespace hardware
} // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 6f26450..b5e4dfe 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -124,14 +124,14 @@
{
sp<IBinder> context = getStrongProxyForHandle(0);
- if (context == nullptr) {
- ALOGW("Not able to get context object on %s.", mDriverName.c_str());
+ if (context) {
+ // The root object is special since we get it directly from the driver, it is never
+ // written by Parcell::writeStrongBinder.
+ internal::Stability::markCompilationUnit(context.get());
+ } else {
+ ALOGW("Not able to get context object on %s.", mDriverName.c_str());
}
- // The root object is special since we get it directly from the driver, it is never
- // written by Parcell::writeStrongBinder.
- internal::Stability::markCompilationUnit(context.get());
-
return context;
}
diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h
index d18c88e..73893c7 100644
--- a/libs/binder/include/binder/LazyServiceRegistrar.h
+++ b/libs/binder/include/binder/LazyServiceRegistrar.h
@@ -16,6 +16,8 @@
#pragma once
+#include <functional>
+
#include <binder/IServiceManager.h>
#include <binder/Status.h>
#include <utils/StrongPointer.h>
@@ -53,6 +55,40 @@
*/
void forcePersist(bool persist);
+ /**
+ * Set a callback that is executed when the total number of services with
+ * clients changes.
+ * The callback takes an argument, which is the number of registered
+ * lazy services for this process which have clients.
+ *
+ * Callback return value:
+ * - false: Default behavior for lazy services (shut down the process if there
+ * are no clients).
+ * - true: Don't shut down the process even if there are no clients.
+ *
+ * This callback gives a chance to:
+ * 1 - Perform some additional operations before exiting;
+ * 2 - Prevent the process from exiting by returning "true" from the
+ * callback.
+ *
+ * This method should be called before 'registerService' to avoid races.
+ */
+ void setActiveServicesCountCallback(const std::function<bool(int)>&
+ activeServicesCountCallback);
+
+ /**
+ * Try to unregister all services previously registered with 'registerService'.
+ * Returns 'true' if successful.
+ */
+ bool tryUnregister();
+
+ /**
+ * Re-register services that were unregistered by 'tryUnregister'.
+ * This method should be called in the case 'tryUnregister' fails
+ * (and should be called on the same thread).
+ */
+ void reRegister();
+
private:
std::shared_ptr<internal::ClientCounterCallback> mClientCC;
LazyServiceRegistrar();
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index ce5027e..ff0a686 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -52,80 +52,80 @@
}
template <typename T>
- bool setParcelable(T&& p) {
+ status_t setParcelable(T&& p) {
using Tt = typename std::decay<T>::type;
return setParcelable<Tt>(std::make_shared<Tt>(std::forward<T>(p)));
}
template <typename T>
- bool setParcelable(std::shared_ptr<T> p) {
+ status_t setParcelable(std::shared_ptr<T> p) {
static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
if (p && this->getStability() > p->getStability()) {
- return false;
+ return android::BAD_VALUE;
}
this->mParcelable = p;
this->mParcelableName = T::getParcelableDescriptor();
this->mParcelPtr = nullptr;
- return true;
+ return android::OK;
}
template <typename T>
- std::shared_ptr<T> getParcelable() const {
+ status_t getParcelable(std::shared_ptr<T>* ret) const {
static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
const std::string& parcelableDesc = T::getParcelableDescriptor();
if (!this->mParcelPtr) {
if (!this->mParcelable || !this->mParcelableName) {
ALOGD("empty ParcelableHolder");
- return nullptr;
+ *ret = nullptr;
+ return android::OK;
} else if (parcelableDesc != *mParcelableName) {
ALOGD("extension class name mismatch expected:%s actual:%s",
mParcelableName->c_str(), parcelableDesc.c_str());
- return nullptr;
+ *ret = nullptr;
+ return android::BAD_VALUE;
}
- return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ return android::OK;
}
this->mParcelPtr->setDataPosition(0);
status_t status = this->mParcelPtr->readUtf8FromUtf16(&this->mParcelableName);
if (status != android::OK || parcelableDesc != this->mParcelableName) {
this->mParcelableName = std::nullopt;
- return nullptr;
+ *ret = nullptr;
+ return status;
}
this->mParcelable = std::make_shared<T>();
status = mParcelable.get()->readFromParcel(this->mParcelPtr.get());
if (status != android::OK) {
this->mParcelableName = std::nullopt;
this->mParcelable = nullptr;
- return nullptr;
+ *ret = nullptr;
+ return status;
}
this->mParcelPtr = nullptr;
- return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+ return android::OK;
}
Stability getStability() const override { return mStability; }
inline bool operator!=(const ParcelableHolder& rhs) const {
- return std::tie(mParcelable, mParcelPtr, mStability) !=
- std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ return this != &rhs;
}
inline bool operator<(const ParcelableHolder& rhs) const {
- return std::tie(mParcelable, mParcelPtr, mStability) <
- std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ return this < &rhs;
}
inline bool operator<=(const ParcelableHolder& rhs) const {
- return std::tie(mParcelable, mParcelPtr, mStability) <=
- std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ return this <= &rhs;
}
inline bool operator==(const ParcelableHolder& rhs) const {
- return std::tie(mParcelable, mParcelPtr, mStability) ==
- std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ return this == &rhs;
}
inline bool operator>(const ParcelableHolder& rhs) const {
- return std::tie(mParcelable, mParcelPtr, mStability) >
- std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ return this > &rhs;
}
inline bool operator>=(const ParcelableHolder& rhs) const {
- return std::tie(mParcelable, mParcelPtr, mStability) >=
- std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability);
+ return this >= &rhs;
}
private:
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index cf2b9e9..6636a41 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -82,56 +82,47 @@
}
template <typename T>
- bool setParcelable(const T& p) {
+ binder_status_t setParcelable(const T& p) {
if (this->mStability > T::_aidl_stability) {
- return false;
+ return STATUS_BAD_VALUE;
}
AParcel_reset(mParcel.get());
AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
p.writeToParcel(mParcel.get());
- return true;
+ return STATUS_OK;
}
template <typename T>
- std::unique_ptr<T> getParcelable() const {
+ binder_status_t getParcelable(std::optional<T>* ret) const {
const std::string parcelableDesc(T::descriptor);
AParcel_setDataPosition(mParcel.get(), 0);
if (AParcel_getDataSize(mParcel.get()) == 0) {
- return nullptr;
+ *ret = std::nullopt;
+ return STATUS_OK;
}
std::string parcelableDescInParcel;
binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) {
- return nullptr;
+ *ret = std::nullopt;
+ return status;
}
- std::unique_ptr<T> ret = std::make_unique<T>();
- status = ret->readFromParcel(this->mParcel.get());
+ *ret = std::make_optional<T>();
+ status = (*ret)->readFromParcel(this->mParcel.get());
if (status != STATUS_OK) {
- return nullptr;
+ *ret = std::nullopt;
+ return status;
}
- return std::move(ret);
+ return STATUS_OK;
}
void reset() { AParcel_reset(mParcel.get()); }
- inline bool operator!=(const AParcelableHolder& rhs) const {
- return std::tie(mParcel, mStability) != std::tie(rhs.mParcel, rhs.mStability);
- }
- inline bool operator<(const AParcelableHolder& rhs) const {
- return std::tie(mParcel, mStability) < std::tie(rhs.mParcel, rhs.mStability);
- }
- inline bool operator<=(const AParcelableHolder& rhs) const {
- return std::tie(mParcel, mStability) <= std::tie(rhs.mParcel, rhs.mStability);
- }
- inline bool operator==(const AParcelableHolder& rhs) const {
- return std::tie(mParcel, mStability) == std::tie(rhs.mParcel, rhs.mStability);
- }
- inline bool operator>(const AParcelableHolder& rhs) const {
- return std::tie(mParcel, mStability) > std::tie(rhs.mParcel, rhs.mStability);
- }
- inline bool operator>=(const AParcelableHolder& rhs) const {
- return std::tie(mParcel, mStability) >= std::tie(rhs.mParcel, rhs.mStability);
- }
+ inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; }
+ inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; }
+ inline bool operator<=(const AParcelableHolder& rhs) const { return this <= &rhs; }
+ inline bool operator==(const AParcelableHolder& rhs) const { return this == &rhs; }
+ inline bool operator>(const AParcelableHolder& rhs) const { return this > &rhs; }
+ inline bool operator>=(const AParcelableHolder& rhs) const { return this >= &rhs; }
private:
mutable ndk::ScopedAParcel mParcel;
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index af9ef06..7dd584d 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -38,9 +38,10 @@
cc_library_shared {
name: "libgui",
- vendor_available: false,
+ vendor_available: true,
vndk: {
enabled: true,
+ private: true,
},
double_loadable: true,
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index ee5552f..eaa47f9 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -371,7 +371,7 @@
mPendingTransactions.end());
if (applyTransaction) {
- t->apply();
+ t->setApplyToken(mApplyToken).apply();
}
BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
@@ -600,6 +600,14 @@
return BufferQueueProducer::connect(new AsyncProducerListener(listener), api,
producerControlledByApp, output);
}
+
+ int query(int what, int* value) override {
+ if (what == NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER) {
+ *value = 1;
+ return NO_ERROR;
+ }
+ return BufferQueueProducer::query(what, value);
+ }
};
// Similar to BufferQueue::createBufferQueue but creates an adapter specific bufferqueue producer.
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 94390aa..1bba5e4 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -985,6 +985,10 @@
}
break;
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
+ status_t err = mGraphicBufferProducer->query(what, value);
+ if (err == NO_ERROR) {
+ return NO_ERROR;
+ }
if (composerService()->authenticateSurfaceTexture(
mGraphicBufferProducer)) {
*value = 1;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 5570d99..97c2693 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -396,7 +396,8 @@
mContainsBuffer(other.mContainsBuffer),
mDesiredPresentTime(other.mDesiredPresentTime),
mIsAutoTimestamp(other.mIsAutoTimestamp),
- mFrameTimelineVsyncId(other.mFrameTimelineVsyncId) {
+ mFrameTimelineVsyncId(other.mFrameTimelineVsyncId),
+ mApplyToken(other.mApplyToken) {
mDisplayStates = other.mDisplayStates;
mComposerStates = other.mComposerStates;
mInputWindowCommands = other.mInputWindowCommands;
@@ -427,7 +428,8 @@
const int64_t desiredPresentTime = parcel->readInt64();
const bool isAutoTimestamp = parcel->readBool();
const int64_t frameTimelineVsyncId = parcel->readInt64();
-
+ sp<IBinder> applyToken;
+ parcel->readNullableStrongBinder(&applyToken);
size_t count = static_cast<size_t>(parcel->readUint32());
if (count > parcel->dataSize()) {
return BAD_VALUE;
@@ -505,6 +507,7 @@
mListenerCallbacks = listenerCallbacks;
mComposerStates = composerStates;
mInputWindowCommands = inputWindowCommands;
+ mApplyToken = applyToken;
return NO_ERROR;
}
@@ -532,6 +535,7 @@
parcel->writeInt64(mDesiredPresentTime);
parcel->writeBool(mIsAutoTimestamp);
parcel->writeInt64(mFrameTimelineVsyncId);
+ parcel->writeStrongBinder(mApplyToken);
parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
for (auto const& displayState : mDisplayStates) {
displayState.write(*parcel);
@@ -607,6 +611,7 @@
mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart;
mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd;
+ mApplyToken = other.mApplyToken;
// When merging vsync Ids we take the oldest one
if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID &&
@@ -635,6 +640,7 @@
mDesiredPresentTime = 0;
mIsAutoTimestamp = true;
mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
+ mApplyToken = nullptr;
}
void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
@@ -763,7 +769,10 @@
flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd;
}
- sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ sp<IBinder> applyToken = mApplyToken
+ ? mApplyToken
+ : IInterface::asBinder(TransactionCompletedListener::getIInstance());
+
sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken,
mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
{} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
@@ -1579,6 +1588,12 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken(
+ const sp<IBinder>& applyToken) {
+ mApplyToken = applyToken;
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index c4cdb65..1198135 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -165,6 +165,10 @@
std::function<void(int64_t)> mTransactionCompleteCallback GUARDED_BY(mMutex) = nullptr;
uint64_t mTransactionCompleteFrameNumber GUARDED_BY(mMutex){0};
+
+ // Queues up transactions using this token in SurfaceFlinger. This prevents queued up
+ // transactions from other parts of the client from blocking this transaction.
+ const sp<IBinder> mApplyToken = new BBinder();
};
} // namespace android
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0abe72c..48bc5d5 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -388,6 +388,10 @@
// The vsync Id provided by Choreographer.getVsyncId
int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
+ // If not null, transactions will be queued up using this token otherwise a common token
+ // per process will be used.
+ sp<IBinder> mApplyToken = nullptr;
+
InputWindowCommands mInputWindowCommands;
int mStatus = NO_ERROR;
@@ -555,6 +559,11 @@
// in shared buffer mode.
Transaction& setAutoRefresh(const sp<SurfaceControl>& sc, bool autoRefresh);
+ // Queues up transactions using this token in SurfaceFlinger. By default, all transactions
+ // from a client are placed on the same queue. This can be used to prevent multiple
+ // transactions from blocking each other.
+ Transaction& setApplyToken(const sp<IBinder>& token);
+
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 17f8b97..d69b7c3 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -24,6 +24,7 @@
#include <gui/FrameTimestamps.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
+#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SyncScreenCaptureListener.h>
#include <private/gui/ComposerService.h>
@@ -220,6 +221,32 @@
return captureResults.result;
}
+ void queueBuffer(sp<IGraphicBufferProducer> igbp, uint8_t r, uint8_t g, uint8_t b,
+ nsecs_t presentTimeDelay) {
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ auto ret = igbp->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
+ PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr);
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+ ASSERT_EQ(OK, igbp->requestBuffer(slot, &buf));
+
+ uint32_t* bufData;
+ buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN),
+ reinterpret_cast<void**>(&bufData));
+ fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight() / 2), buf->getStride(), r, g, b);
+ buf->unlock();
+
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ nsecs_t timestampNanos = systemTime() + presentTimeDelay;
+ IGraphicBufferProducer::QueueBufferInput input(timestampNanos, false, HAL_DATASPACE_UNKNOWN,
+ Rect(mDisplayWidth, mDisplayHeight / 2),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
+ Fence::NO_FENCE);
+ igbp->queueBuffer(slot, input, &qbOutput);
+ }
+
sp<SurfaceComposerClient> mClient;
sp<ISurfaceComposer> mComposer;
@@ -515,6 +542,53 @@
adapter.waitForCallbacks();
}
+TEST_F(BLASTBufferQueueTest, QueryNativeWindowQueuesToWindowComposer) {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<android::Surface> surface = new Surface(adapter.getIGraphicBufferProducer());
+ ANativeWindow* nativeWindow = (ANativeWindow*)(surface.get());
+ int queuesToNativeWindow = 0;
+ int err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+ &queuesToNativeWindow);
+ ASSERT_EQ(NO_ERROR, err);
+ ASSERT_EQ(queuesToNativeWindow, 1);
+}
+
+TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) {
+ sp<SurfaceControl> bgSurface =
+ mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+ ASSERT_NE(nullptr, bgSurface.get());
+ Transaction t;
+ t.setLayerStack(bgSurface, 0)
+ .show(bgSurface)
+ .setDataspace(bgSurface, ui::Dataspace::V0_SRGB)
+ .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+ .setLayer(bgSurface, std::numeric_limits<int32_t>::max() - 1)
+ .apply();
+
+ BLASTBufferQueueHelper slowAdapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> slowIgbProducer;
+ setUpProducer(slowAdapter, slowIgbProducer);
+ nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+ queueBuffer(slowIgbProducer, 0 /* r */, 0 /* g */, 0 /* b */, presentTimeDelay);
+
+ BLASTBufferQueueHelper fastAdapter(bgSurface, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> fastIgbProducer;
+ setUpProducer(fastAdapter, fastIgbProducer);
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+ queueBuffer(fastIgbProducer, r, g, b, 0 /* presentTimeDelay */);
+ fastAdapter.waitForCallbacks();
+
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest {
public:
void test(uint32_t tr) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 3d6b7af..46ae18c 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -672,13 +672,17 @@
? getSkRect(layer->geometry.roundedCornersCrop)
: dest;
drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
+ } else {
+ // Shadows are assumed to live only on their own layer - it's not valid
+ // to draw the boundary retangles when there is already a caster shadow
+ // TODO(b/175915334): consider relaxing this restriction to enable more flexible
+ // composition - using a well-defined invalid color is long-term less error-prone.
+ // Push the clipRRect onto the clip stack. Draw the image. Pop the clip.
+ if (layer->geometry.roundedCornersRadius > 0) {
+ canvas->clipRRect(getRoundedRect(layer), true);
+ }
+ canvas->drawRect(dest, paint);
}
-
- // Push the clipRRect onto the clip stack. Draw the image. Pop the clip.
- if (layer->geometry.roundedCornersRadius > 0) {
- canvas->clipRRect(getRoundedRect(layer), true);
- }
- canvas->drawRect(dest, paint);
canvas->restore();
}
canvas->restore();
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index d9dfd8c..15fb1b8 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -20,6 +20,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <chrono>
#include <condition_variable>
@@ -305,6 +306,26 @@
backgroundColor.a);
}
+ void expectShadowColorWithoutCaster(const FloatRect& casterBounds,
+ const renderengine::ShadowSettings& shadow,
+ const ubyte4& backgroundColor) {
+ const float shadowInset = shadow.length * -1.0f;
+ const Rect casterRect(casterBounds);
+ const Rect shadowRect =
+ Rect(casterRect).inset(shadowInset, shadowInset, shadowInset, shadowInset);
+
+ const Region backgroundRegion =
+ Region(fullscreenRect()).subtractSelf(casterRect).subtractSelf(shadowRect);
+
+ expectAlpha(shadowRect, 255);
+ // (0, 0, 0) fill on the bounds of the layer should be ignored.
+ expectBufferColor(casterRect, 255, 255, 255, 255, 254);
+
+ // verify background
+ expectBufferColor(backgroundRegion, backgroundColor.r, backgroundColor.g, backgroundColor.b,
+ backgroundColor.a);
+ }
+
static renderengine::ShadowSettings getShadowSettings(const vec2& casterPos, float shadowLength,
bool casterIsTranslucent) {
renderengine::ShadowSettings shadow;
@@ -446,6 +467,10 @@
const renderengine::ShadowSettings& shadow, const ubyte4& casterColor,
const ubyte4& backgroundColor);
+ void drawShadowWithoutCaster(const FloatRect& castingBounds,
+ const renderengine::ShadowSettings& shadow,
+ const ubyte4& backgroundColor);
+
std::unique_ptr<renderengine::gl::GLESRenderEngine> mRE;
// Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to
@@ -1118,6 +1143,37 @@
invokeDraw(settings, layers, mBuffer);
}
+void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds,
+ const renderengine::ShadowSettings& shadow,
+ const ubyte4& backgroundColor) {
+ renderengine::DisplaySettings settings;
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+
+ std::vector<const renderengine::LayerSettings*> layers;
+
+ // add background layer
+ renderengine::LayerSettings bgLayer;
+ bgLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+ bgLayer.geometry.boundaries = fullscreenRect().toFloatRect();
+ ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f,
+ backgroundColor.b / 255.0f, this);
+ bgLayer.alpha = backgroundColor.a / 255.0f;
+ layers.push_back(&bgLayer);
+
+ // add shadow layer
+ renderengine::LayerSettings shadowLayer;
+ shadowLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+ shadowLayer.geometry.boundaries = castingBounds;
+ shadowLayer.alpha = 1.0f;
+ ColorSourceVariant::fillColor(shadowLayer, 0, 0, 0, this);
+ shadowLayer.shadow = shadow;
+ layers.push_back(&shadowLayer);
+
+ invokeDraw(settings, layers, mBuffer);
+}
+
INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
testing::Values(std::make_shared<GLESRenderEngineFactory>(),
std::make_shared<GLESCMRenderEngineFactory>(),
@@ -1608,6 +1664,22 @@
EXPECT_FALSE(mRE->isImageCachedForTesting(bufferId));
}
+TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) {
+ const auto& renderEngineFactory = GetParam();
+ mRE = renderEngineFactory->createRenderEngine();
+
+ const ubyte4 backgroundColor(255, 255, 255, 255);
+ const float shadowLength = 5.0f;
+ Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f);
+ casterBounds.offsetBy(shadowLength + 1, shadowLength + 1);
+ renderengine::ShadowSettings settings =
+ getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength,
+ false /* casterIsTranslucent */);
+
+ drawShadowWithoutCaster(casterBounds.toFloatRect(), settings, backgroundColor);
+ expectShadowColorWithoutCaster(casterBounds.toFloatRect(), settings, backgroundColor);
+}
+
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) {
const auto& renderEngineFactory = GetParam();
mRE = renderEngineFactory->createRenderEngine();
@@ -1844,4 +1916,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 48abdce..8b94f61 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -54,6 +54,7 @@
cc_library_headers {
name: "gl_headers",
+ host_supported: true,
vendor_available: true,
export_include_dirs: ["include"],
}
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 398efc0..f576660 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -128,6 +128,7 @@
"EGL_KHR_stream_producer_eglsurface "
"EGL_KHR_surfaceless_context "
"EGL_KHR_wait_sync " // strongly recommended
+ "EGL_NV_context_priority_realtime "
"EGL_NV_system_time "
;
diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp
index 6235f06..0d17265 100644
--- a/services/audiomanager/IAudioManager.cpp
+++ b/services/audiomanager/IAudioManager.cpp
@@ -84,11 +84,13 @@
return remote()->transact(PLAYER_ATTRIBUTES, data, &reply, IBinder::FLAG_ONEWAY);
}
- virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event) {
+ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
+ audio_port_handle_t deviceId) {
Parcel data, reply;
data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
data.writeInt32((int32_t) piid);
data.writeInt32((int32_t) event);
+ data.writeInt32((int32_t) deviceId);
return remote()->transact(PLAYER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5832109..f3d969e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -321,6 +321,17 @@
static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
std::shared_ptr<EventEntry> eventEntry,
int32_t inputTargetFlags) {
+ if (eventEntry->type == EventEntry::Type::MOTION) {
+ const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
+ if (motionEntry.source & AINPUT_SOURCE_CLASS_JOYSTICK) {
+ const ui::Transform identityTransform;
+ // Use identity transform for joystick events events because they don't depend on
+ // the window info
+ return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, identityTransform,
+ 1.0f /*globalScaleFactor*/);
+ }
+ }
+
if (inputTarget.useDefaultPointerTransform()) {
const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
@@ -434,6 +445,14 @@
return interface_cast<IPlatformCompatNative>(service);
}
+static KeyEvent createKeyEvent(const KeyEntry& entry) {
+ KeyEvent event;
+ event.initialize(entry.id, entry.deviceId, entry.source, entry.displayId, INVALID_HMAC,
+ entry.action, entry.flags, entry.keyCode, entry.scanCode, entry.metaState,
+ entry.repeatCount, entry.downTime, entry.eventTime);
+ return event;
+}
+
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -3206,8 +3225,8 @@
void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options) {
- for (const auto& pair : mConnectionsByFd) {
- synthesizeCancelationEventsForConnectionLocked(pair.second, options);
+ for (const auto& [fd, connection] : mConnectionsByFd) {
+ synthesizeCancelationEventsForConnectionLocked(connection, options);
}
}
@@ -3414,7 +3433,9 @@
// The first/last pointer went down/up.
action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN
? AMOTION_EVENT_ACTION_DOWN
- : AMOTION_EVENT_ACTION_UP;
+ : (originalMotionEntry.flags & AMOTION_EVENT_FLAG_CANCELED) != 0
+ ? AMOTION_EVENT_ACTION_CANCEL
+ : AMOTION_EVENT_ACTION_UP;
} else {
// A secondary pointer went down/up.
uint32_t splitPointerIndex = 0;
@@ -5638,14 +5659,6 @@
mLock.lock();
}
-KeyEvent InputDispatcher::createKeyEvent(const KeyEntry& entry) {
- KeyEvent event;
- event.initialize(entry.id, entry.deviceId, entry.source, entry.displayId, INVALID_HMAC,
- entry.action, entry.flags, entry.keyCode, entry.scanCode, entry.metaState,
- entry.repeatCount, entry.downTime, entry.eventTime);
- return event;
-}
-
void InputDispatcher::reportDispatchStatistics(std::chrono::nanoseconds eventDuration,
const Connection& connection, bool handled) {
// TODO Write some statistics about how long we spend waiting.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 4806a27..df0be99 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -610,7 +610,6 @@
DispatchEntry* dispatchEntry, MotionEntry& motionEntry,
bool handled) REQUIRES(mLock);
void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- KeyEvent createKeyEvent(const KeyEntry& entry);
void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
// Statistics gathering.
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index ac72ac4..c7c8e7c 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -54,10 +54,11 @@
if (!hasEventHubDevices()) {
return false;
}
- // devices are either all enabled or all disabled, so we only need to check the first
- auto& devicePair = mDevices.begin()->second;
- auto& contextPtr = devicePair.first;
- return contextPtr->isDeviceEnabled();
+ // An input device composed of sub devices can be individually enabled or disabled.
+ // If any of the sub device is enabled then the input device is considered as enabled.
+ bool enabled = false;
+ for_each_subdevice([&enabled](auto& context) { enabled |= context.isDeviceEnabled(); });
+ return enabled;
}
void InputDevice::setEnabled(bool enabled, nsecs_t when) {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index be21ace..6c493ff 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -222,7 +222,9 @@
}
// Sensor input device is noisy, to save power disable it by default.
- if (device->getClasses().test(InputDeviceClass::SENSOR)) {
+ // Input device is classified as SENSOR when any sub device is a SENSOR device, check Eventhub
+ // device class to disable SENSOR sub device only.
+ if (mEventHub->getDeviceClasses(eventHubId).test(InputDeviceClass::SENSOR)) {
mEventHub->disableDevice(eventHubId);
}
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 0b30ff5..6dbc88f 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -862,6 +862,8 @@
void setWindowScale(float xScale, float yScale) { setWindowTransform(xScale, 0, 0, yScale); }
+ void setWindowOffset(float offsetX, float offsetY) { mInfo.transform.set(offsetX, offsetY); }
+
void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
consumeEvent(AINPUT_EVENT_TYPE_KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId,
expectedFlags);
@@ -1785,6 +1787,71 @@
window->assertNoEvents(); // Key event or focus event will not be received
}
+TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ // Create first non touch modal window that supports split touch
+ sp<FakeWindowHandle> firstWindow =
+ new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ firstWindow->setFrame(Rect(0, 0, 600, 400));
+ firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
+ InputWindowInfo::Flag::SPLIT_TOUCH);
+
+ // Create second non touch modal window that supports split touch
+ sp<FakeWindowHandle> secondWindow =
+ new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ secondWindow->setFrame(Rect(0, 400, 600, 800));
+ secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
+ InputWindowInfo::Flag::SPLIT_TOUCH);
+
+ // Add the windows to the dispatcher
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
+
+ PointF pointInFirst = {300, 200};
+ PointF pointInSecond = {300, 600};
+
+ // Send down to the first window
+ NotifyMotionArgs firstDownMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {pointInFirst});
+ mDispatcher->notifyMotion(&firstDownMotionArgs);
+ // Only the first window should get the down event
+ firstWindow->consumeMotionDown();
+ secondWindow->assertNoEvents();
+
+ // Send down to the second window
+ NotifyMotionArgs secondDownMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {pointInFirst, pointInSecond});
+ mDispatcher->notifyMotion(&secondDownMotionArgs);
+ // The first window gets a move and the second a down
+ firstWindow->consumeMotionMove();
+ secondWindow->consumeMotionDown();
+
+ // Send pointer cancel to the second window
+ NotifyMotionArgs pointerUpMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {pointInFirst, pointInSecond});
+ pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
+ mDispatcher->notifyMotion(&pointerUpMotionArgs);
+ // The first window gets move and the second gets cancel.
+ firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
+ secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
+
+ // Send up event.
+ NotifyMotionArgs upMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&upMotionArgs);
+ // The first window gets up and the second gets nothing.
+ firstWindow->consumeMotionUp();
+ secondWindow->assertNoEvents();
+}
+
class FakeMonitorReceiver {
public:
FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
@@ -2051,6 +2118,50 @@
EXPECT_EQ(motionArgs.buttonState, verifiedMotion.buttonState);
}
+TEST_F(InputDispatcherTest, NonPointerMotionEvent_JoystickNotTransformed) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ const std::string name = window->getName();
+
+ // Window gets transformed by offset values.
+ window->setWindowOffset(500.0f, 500.0f);
+
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ window->setFocusable(true);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ // First, we set focused window so that focusedWindowHandle is not null.
+ setFocusedWindow(window);
+
+ // Second, we consume focus event if it is right or wrong according to onFocusChangedLocked.
+ window->consumeFocusEvent(true);
+
+ NotifyMotionArgs motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_MOVE,
+ AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+
+ // Third, we consume motion event.
+ InputEvent* event = window->consume();
+ ASSERT_NE(event, nullptr);
+ ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
+ << name.c_str() << "expected " << inputEventTypeToString(AINPUT_EVENT_TYPE_MOTION)
+ << " event, got " << inputEventTypeToString(event->getType()) << " event";
+
+ const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event);
+ EXPECT_EQ(AINPUT_EVENT_TYPE_MOTION, motionEvent.getAction());
+
+ float expectedX = motionArgs.pointerCoords[0].getX();
+ float expectedY = motionArgs.pointerCoords[0].getY();
+
+ // Finally we test if the axis values from the final motion event are not transformed
+ EXPECT_EQ(expectedX, motionEvent.getX(0)) << "expected " << expectedX << " for x coord of "
+ << name.c_str() << ", got " << motionEvent.getX(0);
+ EXPECT_EQ(expectedY, motionEvent.getY(0)) << "expected " << expectedY << " for y coord of "
+ << name.c_str() << ", got " << motionEvent.getY(0);
+}
+
/**
* Ensure that separate calls to sign the same data are generating the same key.
* We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 3e7a03e..91d5864 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1481,6 +1481,32 @@
ASSERT_EQ(1U, mReader->getInputDevices().size());
}
+TEST_F(InputReaderTest, GetMergedInputDevicesEnabled) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};
+ // Add two subdevices to device
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
+ // Must add at least one mapper or the device will be ignored!
+ device->addMapper<FakeInputMapper>(eventHubIds[0], AINPUT_SOURCE_KEYBOARD);
+ device->addMapper<FakeInputMapper>(eventHubIds[1], AINPUT_SOURCE_KEYBOARD);
+
+ // Push same device instance for next device to be added, so they'll have same identifier.
+ mReader->pushNextDevice(device);
+ mReader->pushNextDevice(device);
+ // Sensor device is initially disabled
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "fake1",
+ InputDeviceClass::KEYBOARD | InputDeviceClass::SENSOR,
+ nullptr));
+ // Device is disabled because the only sub device is a sensor device and disabled initially.
+ ASSERT_FALSE(mFakeEventHub->isDeviceEnabled(eventHubIds[0]));
+ ASSERT_FALSE(device->isEnabled());
+ ASSERT_NO_FATAL_FAILURE(
+ addDevice(eventHubIds[1], "fake2", InputDeviceClass::KEYBOARD, nullptr));
+ // The merged device is enabled if any sub device is enabled
+ ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(eventHubIds[1]));
+ ASSERT_TRUE(device->isEnabled());
+}
+
TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
constexpr Flags<InputDeviceClass> deviceClass(InputDeviceClass::KEYBOARD);
@@ -2721,6 +2747,7 @@
ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::ACCELEROMETER,
std::chrono::microseconds(10000),
std::chrono::microseconds(0)));
+ ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(EVENTHUB_ID));
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_X, 20000);
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_Y, -20000);
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_Z, 40000);
@@ -2750,6 +2777,7 @@
ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::GYROSCOPE,
std::chrono::microseconds(10000),
std::chrono::microseconds(0)));
+ ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(EVENTHUB_ID));
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_RX, 20000);
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_RY, -20000);
process(mapper, ARBITRARY_TIME, EV_ABS, ABS_RZ, 40000);
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index fdb8aaf..a7cd258 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -3,6 +3,7 @@
cflags: [
"-Wall",
"-Werror",
+ "-Wextra",
"-Wformat",
"-Wthread-safety",
"-Wunused",
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e8e31db..04cec4f 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#undef LOG_TAG
#define LOG_TAG "BufferQueueLayer"
@@ -661,4 +662,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 7ec7f36..bca1c69 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
//#define LOG_NDEBUG 0
#undef LOG_TAG
@@ -870,4 +871,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
index 67e6deb..df44e75 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
@@ -22,11 +22,12 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <ui/GraphicTypes.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
namespace android {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
index 7eb8eb1..1136e3d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
@@ -23,11 +23,12 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <ui/GraphicTypes.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
#include <ui/HdrCapabilities.h>
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 26f7f68..018a687 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -23,11 +23,12 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <renderengine/LayerSettings.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
#include <utils/RefBase.h>
#include <utils/Timers.h>
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 5a3b9ac..c445d5b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -29,6 +29,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <gui/BufferQueue.h>
#include <ui/GraphicBuffer.h>
@@ -37,7 +38,7 @@
#include "DisplayHardware/Hal.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
namespace android::compositionengine {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index aa70ef8..fb19216 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -25,12 +25,13 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/DisplayIdentification.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
namespace android {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index 2864c10..aa049a8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -22,11 +22,12 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <gui/BufferQueue.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
#include <utils/StrongPointer.h>
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 06e6a6f..8f767d3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -23,11 +23,12 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <ui/GraphicTypes.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
#include <compositionengine/ProjectionSpace.h>
#include <ui/Rect.h>
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index d2b38d1..9a118d3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -30,11 +30,12 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include "DisplayHardware/ComposerHal.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
namespace android {
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 1befbf8..348ec39 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#include <cmath>
#include <compositionengine/DisplayColorProfileCreationArgs.h>
@@ -1043,3 +1047,6 @@
} // namespace
} // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index 87911cc..9518659 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -27,12 +27,13 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <ui/GraphicTypes.h>
#include "DisplayHardware/HWC2.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
namespace android {
namespace HWC2 {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 84c027b..e64a9f1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -22,11 +22,12 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include "DisplayHardware/HWComposer.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
namespace android {
namespace mock {
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 6ce8a6b..cd39733 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#include <cstdarg>
#include <cstdint>
@@ -359,3 +363,6 @@
} // namespace
} // namespace android::compositionengine
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 5b66809..c756d65 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -26,6 +26,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/composer/2.4/IComposer.h>
@@ -38,7 +39,7 @@
#include <utils/StrongPointer.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
namespace android {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 5fa72b8..6f3987f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -74,6 +74,7 @@
namespace hal = android::hardware::graphics::composer::hal;
+namespace android {
namespace {
using android::hardware::Return;
@@ -88,47 +89,46 @@
mSequenceId(sequenceId),
mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
- android::hardware::Return<void> onHotplug(hal::HWDisplayId display,
- hal::Connection conn) override {
+ Return<void> onHotplug(hal::HWDisplayId display, hal::Connection conn) override {
mCallback->onHotplugReceived(mSequenceId, display, conn);
- return android::hardware::Void();
+ return Void();
}
- android::hardware::Return<void> onRefresh(hal::HWDisplayId display) override {
+ Return<void> onRefresh(hal::HWDisplayId display) override {
mCallback->onRefreshReceived(mSequenceId, display);
- return android::hardware::Void();
+ return Void();
}
- android::hardware::Return<void> onVsync(hal::HWDisplayId display, int64_t timestamp) override {
+ Return<void> onVsync(hal::HWDisplayId display, int64_t timestamp) override {
if (!mVsyncSwitchingSupported) {
mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::nullopt);
} else {
ALOGW("Unexpected onVsync callback on composer >= 2.4, ignoring.");
}
- return android::hardware::Void();
+ return Void();
}
- android::hardware::Return<void> onVsync_2_4(hal::HWDisplayId display, int64_t timestamp,
- hal::VsyncPeriodNanos vsyncPeriodNanos) override {
+ Return<void> onVsync_2_4(hal::HWDisplayId display, int64_t timestamp,
+ hal::VsyncPeriodNanos vsyncPeriodNanos) override {
if (mVsyncSwitchingSupported) {
mCallback->onVsyncReceived(mSequenceId, display, timestamp,
std::make_optional(vsyncPeriodNanos));
} else {
ALOGW("Unexpected onVsync_2_4 callback on composer <= 2.3, ignoring.");
}
- return android::hardware::Void();
+ return Void();
}
- android::hardware::Return<void> onVsyncPeriodTimingChanged(
+ Return<void> onVsyncPeriodTimingChanged(
hal::HWDisplayId display,
const hal::VsyncPeriodChangeTimeline& updatedTimeline) override {
mCallback->onVsyncPeriodTimingChangedReceived(mSequenceId, display, updatedTimeline);
- return android::hardware::Void();
+ return Void();
}
- android::hardware::Return<void> onSeamlessPossible(hal::HWDisplayId display) override {
+ Return<void> onSeamlessPossible(hal::HWDisplayId display) override {
mCallback->onSeamlessPossible(mSequenceId, display);
- return android::hardware::Void();
+ return Void();
}
private:
@@ -139,8 +139,6 @@
} // namespace
-namespace android {
-
HWComposer::~HWComposer() = default;
namespace impl {
@@ -295,6 +293,7 @@
hal::DisplayType::PHYSICAL);
newDisplay->setConnected(true);
displayData.hwcDisplay = std::move(newDisplay);
+ displayData.configs = displayData.hwcDisplay->getConfigs();
mPhysicalDisplayIdMap[hwcDisplayId] = displayId;
}
@@ -335,14 +334,9 @@
PhysicalDisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, {});
- const auto& displayData = mDisplayData.at(displayId);
- auto configs = displayData.hwcDisplay->getConfigs();
- if (displayData.configMap.empty()) {
- for (size_t i = 0; i < configs.size(); ++i) {
- displayData.configMap[i] = configs[i];
- }
- }
- return configs;
+ // We cache the configs when the DisplayData is created on hotplug. If the configs need to
+ // change HWC will send a hotplug event which will recreate displayData.
+ return mDisplayData.at(displayId).configs;
}
std::shared_ptr<const HWC2::Display::Config> HWComposer::getActiveConfig(
@@ -653,13 +647,13 @@
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
- if (displayData.configMap.count(configId) == 0) {
+ if (configId >= displayData.configs.size()) {
LOG_DISPLAY_ERROR(displayId, ("Invalid config " + std::to_string(configId)).c_str());
return BAD_INDEX;
}
auto error =
- displayData.hwcDisplay->setActiveConfigWithConstraints(displayData.configMap[configId],
+ displayData.hwcDisplay->setActiveConfigWithConstraints(displayData.configs[configId],
constraints, outTimeline);
RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
return NO_ERROR;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index d8af5bf..7e1da252 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -32,8 +32,9 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <ui/GraphicTypes.h>
-#pragma clang diagnostic pop
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
@@ -183,7 +184,6 @@
virtual nsecs_t getRefreshTimestamp(PhysicalDisplayId) const = 0;
virtual bool isConnected(PhysicalDisplayId) const = 0;
- // Non-const because it can update configMap inside of mDisplayData
virtual std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(
PhysicalDisplayId) const = 0;
@@ -319,7 +319,6 @@
nsecs_t getRefreshTimestamp(PhysicalDisplayId) const override;
bool isConnected(PhysicalDisplayId) const override;
- // Non-const because it can update configMap inside of mDisplayData
std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(
PhysicalDisplayId) const override;
@@ -378,8 +377,7 @@
std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
buffer_handle_t outbufHandle = nullptr;
sp<Fence> outbufAcquireFence = Fence::NO_FENCE;
- mutable std::unordered_map<int32_t,
- std::shared_ptr<const HWC2::Display::Config>> configMap;
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
bool validateWasSkipped;
hal::Error presentError;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4731f50..a545d18 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -688,6 +688,7 @@
shadowLayer.source.buffer.fence = nullptr;
shadowLayer.frameNumber = 0;
shadowLayer.bufferId = 0;
+ shadowLayer.name = getName();
if (shadowLayer.shadow.ambientColor.a <= 0.f && shadowLayer.shadow.spotColor.a <= 0.f) {
return {};
@@ -723,6 +724,7 @@
// If layer is blacked out, force alpha to 1 so that we draw a black color layer.
layerSettings.alpha = blackout ? 1.0f : 0.0f;
+ layerSettings.name = getName();
}
std::vector<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCompositionList(
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index bc581c2..d6023b6 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -883,7 +883,7 @@
*/
bool hasInputInfo() const;
- uid_t getOwnerUid() { return mOwnerUid; }
+ virtual uid_t getOwnerUid() const { return mOwnerUid; }
pid_t getOwnerPid() { return mOwnerPid; }
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 59fad9b..b1db6d3 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include "LayerProtoHelper.h"
@@ -173,4 +174,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index c291b7f..6a511a8 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <algorithm>
@@ -262,4 +263,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index ad4877b..19b3d6e 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -250,8 +251,7 @@
// If there is relatively little time left for surfaceflinger
// until the next vsync deadline, defer this sampling work
// to a later frame, when hopefully there will be more time.
- DisplayStatInfo stats;
- mScheduler.getDisplayStatInfo(&stats, systemTime());
+ const DisplayStatInfo stats = mScheduler.getDisplayStatInfo(systemTime());
if (std::chrono::nanoseconds(stats.vsyncTime) - now < timeForRegionSampling) {
ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForQuietFrame));
mDiscardedFrames++;
@@ -501,4 +501,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 776da88..170933d 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -142,8 +142,8 @@
const float layerArea = transformed.getWidth() * transformed.getHeight();
float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f;
- summary.push_back(
- {strong->getName(), vote.type, vote.fps, vote.seamlessness, weight, layerFocused});
+ summary.push_back({strong->getName(), strong->getOwnerUid(), vote.type, vote.fps,
+ vote.seamlessness, weight, layerFocused});
if (CC_UNLIKELY(mTraceEnabled)) {
trace(layer, *info, vote.type, vote.fps.getIntValue());
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 4b2862e..0fa71f1 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
// #define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -296,3 +300,6 @@
}
} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 2eb4df1..35b382e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -17,6 +17,10 @@
// #define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#include "RefreshRateConfigs.h"
#include <android-base/stringprintf.h>
#include <utils/Trace.h>
@@ -71,16 +75,84 @@
std::pair<nsecs_t, nsecs_t> RefreshRateConfigs::getDisplayFrames(nsecs_t layerPeriod,
nsecs_t displayPeriod) const {
- auto [displayFramesQuot, displayFramesRem] = std::div(layerPeriod, displayPeriod);
- if (displayFramesRem <= MARGIN_FOR_PERIOD_CALCULATION ||
- std::abs(displayFramesRem - displayPeriod) <= MARGIN_FOR_PERIOD_CALCULATION) {
- displayFramesQuot++;
- displayFramesRem = 0;
+ auto [quotient, remainder] = std::div(layerPeriod, displayPeriod);
+ if (remainder <= MARGIN_FOR_PERIOD_CALCULATION ||
+ std::abs(remainder - displayPeriod) <= MARGIN_FOR_PERIOD_CALCULATION) {
+ quotient++;
+ remainder = 0;
}
- return {displayFramesQuot, displayFramesRem};
+ return {quotient, remainder};
}
+float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer,
+ const RefreshRate& refreshRate,
+ bool isSeamlessSwitch) const {
+ // Slightly prefer seamless switches.
+ constexpr float kSeamedSwitchPenalty = 0.95f;
+ const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
+
+ // If the layer wants Max, give higher score to the higher refresh rate
+ if (layer.vote == LayerVoteType::Max) {
+ const auto ratio =
+ refreshRate.fps.getValue() / mAppRequestRefreshRates.back()->fps.getValue();
+ // use ratio^2 to get a lower score the more we get further from peak
+ return ratio * ratio;
+ }
+
+ const auto displayPeriod = refreshRate.getVsyncPeriod();
+ const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
+ if (layer.vote == LayerVoteType::ExplicitDefault) {
+ // Find the actual rate the layer will render, assuming
+ // that layerPeriod is the minimal time to render a frame
+ auto actualLayerPeriod = displayPeriod;
+ int multiplier = 1;
+ while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
+ multiplier++;
+ actualLayerPeriod = displayPeriod * multiplier;
+ }
+ return std::min(1.0f,
+ static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod));
+ }
+
+ if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
+ layer.vote == LayerVoteType::Heuristic) {
+ // Calculate how many display vsyncs we need to present a single frame for this
+ // layer
+ const auto [displayFramesQuotient, displayFramesRemainder] =
+ getDisplayFrames(layerPeriod, displayPeriod);
+ static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
+ if (displayFramesRemainder == 0) {
+ // Layer desired refresh rate matches the display rate.
+ return 1.0f * seamlessness;
+ }
+
+ if (displayFramesQuotient == 0) {
+ // Layer desired refresh rate is higher than the display rate.
+ return (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
+ (1.0f / (MAX_FRAMES_TO_FIT + 1));
+ }
+
+ // Layer desired refresh rate is lower than the display rate. Check how well it fits
+ // the cadence.
+ auto diff = std::abs(displayFramesRemainder - (displayPeriod - displayFramesRemainder));
+ int iter = 2;
+ while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) {
+ diff = diff - (displayPeriod - diff);
+ iter++;
+ }
+
+ return (1.0f / iter) * seamlessness;
+ }
+
+ return 0;
+}
+
+struct RefreshRateScore {
+ const RefreshRate* refreshRate;
+ float score;
+};
+
const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
GlobalSignals* outSignalsConsidered) const {
@@ -165,11 +237,11 @@
}
// Find the best refresh rate based on score
- std::vector<std::pair<const RefreshRate*, float>> scores;
+ std::vector<RefreshRateScore> scores;
scores.reserve(mAppRequestRefreshRates.size());
for (const auto refreshRate : mAppRequestRefreshRates) {
- scores.emplace_back(refreshRate, 0.0f);
+ scores.emplace_back(RefreshRateScore{refreshRate, 0.0f});
}
const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig);
@@ -184,12 +256,13 @@
auto weight = layer.weight;
for (auto i = 0u; i < scores.size(); i++) {
- const bool isSeamlessSwitch =
- scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup();
+ const bool isSeamlessSwitch = scores[i].refreshRate->getConfigGroup() ==
+ mCurrentRefreshRate->getConfigGroup();
if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) {
ALOGV("%s ignores %s to avoid non-seamless switch. Current config = %s",
- formatLayerInfo(layer, weight).c_str(), scores[i].first->toString().c_str(),
+ formatLayerInfo(layer, weight).c_str(),
+ scores[i].refreshRate->toString().c_str(),
mCurrentRefreshRate->toString().c_str());
continue;
}
@@ -198,7 +271,8 @@
!layer.focused) {
ALOGV("%s ignores %s because it's not focused and the switch is going to be seamed."
" Current config = %s",
- formatLayerInfo(layer, weight).c_str(), scores[i].first->toString().c_str(),
+ formatLayerInfo(layer, weight).c_str(),
+ scores[i].refreshRate->toString().c_str(),
mCurrentRefreshRate->toString().c_str());
continue;
}
@@ -209,18 +283,20 @@
// from the default, this means a layer with seamlessness=SeamedAndSeamless has just
// disappeared.
const bool isInPolicyForDefault = seamedLayers > 0
- ? scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup()
- : scores[i].first->getConfigGroup() == defaultConfig->getConfigGroup();
+ ? scores[i].refreshRate->getConfigGroup() ==
+ mCurrentRefreshRate->getConfigGroup()
+ : scores[i].refreshRate->getConfigGroup() == defaultConfig->getConfigGroup();
if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault &&
!layer.focused) {
ALOGV("%s ignores %s. Current config = %s", formatLayerInfo(layer, weight).c_str(),
- scores[i].first->toString().c_str(), mCurrentRefreshRate->toString().c_str());
+ scores[i].refreshRate->toString().c_str(),
+ mCurrentRefreshRate->toString().c_str());
continue;
}
- bool inPrimaryRange =
- scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max);
+ bool inPrimaryRange = scores[i].refreshRate->inPolicy(policy->primaryRange.min,
+ policy->primaryRange.max);
if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
!(layer.focused && layer.vote == LayerVoteType::ExplicitDefault)) {
// Only focused layers with ExplicitDefault frame rate settings are allowed to score
@@ -228,81 +304,11 @@
continue;
}
- // If the layer wants Max, give higher score to the higher refresh rate
- if (layer.vote == LayerVoteType::Max) {
- const auto ratio =
- scores[i].first->fps.getValue() / scores.back().first->fps.getValue();
- // use ratio^2 to get a lower score the more we get further from peak
- const auto layerScore = ratio * ratio;
- ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
- scores[i].first->getName().c_str(), layerScore);
- scores[i].second += weight * layerScore;
- continue;
- }
-
- const auto displayPeriod = scores[i].first->hwcConfig->getVsyncPeriod();
- const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
- if (layer.vote == LayerVoteType::ExplicitDefault) {
- const auto layerScore = [&]() {
- // Find the actual rate the layer will render, assuming
- // that layerPeriod is the minimal time to render a frame
- auto actualLayerPeriod = displayPeriod;
- int multiplier = 1;
- while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
- multiplier++;
- actualLayerPeriod = displayPeriod * multiplier;
- }
- return std::min(1.0f,
- static_cast<float>(layerPeriod) /
- static_cast<float>(actualLayerPeriod));
- }();
-
- ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
- scores[i].first->getName().c_str(), layerScore);
- scores[i].second += weight * layerScore;
- continue;
- }
-
- if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
- layer.vote == LayerVoteType::Heuristic) {
- const auto layerScore = [&] {
- // Calculate how many display vsyncs we need to present a single frame for this
- // layer
- const auto [displayFramesQuot, displayFramesRem] =
- getDisplayFrames(layerPeriod, displayPeriod);
- static constexpr size_t MAX_FRAMES_TO_FIT =
- 10; // Stop calculating when score < 0.1
- if (displayFramesRem == 0) {
- // Layer desired refresh rate matches the display rate.
- return 1.0f;
- }
-
- if (displayFramesQuot == 0) {
- // Layer desired refresh rate is higher the display rate.
- return (static_cast<float>(layerPeriod) /
- static_cast<float>(displayPeriod)) *
- (1.0f / (MAX_FRAMES_TO_FIT + 1));
- }
-
- // Layer desired refresh rate is lower the display rate. Check how well it fits
- // the cadence
- auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem));
- int iter = 2;
- while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) {
- diff = diff - (displayPeriod - diff);
- iter++;
- }
-
- return 1.0f / iter;
- }();
- // Slightly prefer seamless switches.
- constexpr float kSeamedSwitchPenalty = 0.95f;
- const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
- ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
- scores[i].first->getName().c_str(), layerScore);
- scores[i].second += weight * layerScore * seamlessness;
- continue;
- }
+ const auto layerScore =
+ calculateLayerScoreLocked(layer, *scores[i].refreshRate, isSeamlessSwitch);
+ ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
+ scores[i].refreshRate->getName().c_str(), layerScore);
+ scores[i].score += weight * layerScore;
}
}
@@ -317,7 +323,7 @@
// If we never scored any layers, then choose the rate from the primary
// range instead of picking a random score from the app range.
if (std::all_of(scores.begin(), scores.end(),
- [](std::pair<const RefreshRate*, float> p) { return p.second == 0; })) {
+ [](RefreshRateScore score) { return score.score == 0; })) {
ALOGV("layers not scored - choose %s",
getMaxRefreshRateByPolicyLocked().getName().c_str());
return getMaxRefreshRateByPolicyLocked();
@@ -342,11 +348,111 @@
return *bestRefreshRate;
}
+std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>>
+groupLayersByUid(const std::vector<RefreshRateConfigs::LayerRequirement>& layers) {
+ std::unordered_map<uid_t, std::vector<const RefreshRateConfigs::LayerRequirement*>> layersByUid;
+ for (const auto& layer : layers) {
+ auto iter = layersByUid.emplace(layer.ownerUid,
+ std::vector<const RefreshRateConfigs::LayerRequirement*>());
+ auto& layersWithSameUid = iter.first->second;
+ layersWithSameUid.push_back(&layer);
+ }
+
+ // Remove uids that can't have a frame rate override
+ for (auto iter = layersByUid.begin(); iter != layersByUid.end();) {
+ const auto& layersWithSameUid = iter->second;
+ bool skipUid = false;
+ for (const auto& layer : layersWithSameUid) {
+ if (layer->vote == RefreshRateConfigs::LayerVoteType::Max ||
+ layer->vote == RefreshRateConfigs::LayerVoteType::Heuristic) {
+ skipUid = true;
+ break;
+ }
+ }
+ if (skipUid) {
+ iter = layersByUid.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+
+ return layersByUid;
+}
+
+std::vector<RefreshRateScore> initializeScoresForAllRefreshRates(
+ const AllRefreshRatesMapType& refreshRates) {
+ std::vector<RefreshRateScore> scores;
+ scores.reserve(refreshRates.size());
+ for (const auto& [ignored, refreshRate] : refreshRates) {
+ scores.emplace_back(RefreshRateScore{refreshRate.get(), 0.0f});
+ }
+ std::sort(scores.begin(), scores.end(),
+ [](const auto& a, const auto& b) { return *a.refreshRate < *b.refreshRate; });
+ return scores;
+}
+
+RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverrides(
+ const std::vector<LayerRequirement>& layers, Fps displayFrameRate) const {
+ ATRACE_CALL();
+ if (!mSupportsFrameRateOverride) return {};
+
+ ALOGV("getFrameRateOverrides %zu layers", layers.size());
+ std::lock_guard lock(mLock);
+ std::vector<RefreshRateScore> scores = initializeScoresForAllRefreshRates(mRefreshRates);
+ std::unordered_map<uid_t, std::vector<const LayerRequirement*>> layersByUid =
+ groupLayersByUid(layers);
+ UidToFrameRateOverride frameRateOverrides;
+ for (const auto& [uid, layersWithSameUid] : layersByUid) {
+ for (auto& score : scores) {
+ score.score = 0;
+ }
+
+ for (const auto& layer : layersWithSameUid) {
+ if (layer->vote == LayerVoteType::NoVote || layer->vote == LayerVoteType::Min) {
+ continue;
+ }
+
+ LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault &&
+ layer->vote != LayerVoteType::ExplicitExactOrMultiple);
+ for (RefreshRateScore& score : scores) {
+ const auto layerScore = calculateLayerScoreLocked(*layer, *score.refreshRate,
+ /*isSeamlessSwitch*/ true);
+ score.score += layer->weight * layerScore;
+ }
+ }
+
+ // We just care about the refresh rates which are a divider of the
+ // display refresh rate
+ auto iter =
+ std::remove_if(scores.begin(), scores.end(), [&](const RefreshRateScore& score) {
+ return getFrameRateDivider(displayFrameRate, score.refreshRate->getFps()) == 0;
+ });
+ scores.erase(iter, scores.end());
+
+ // If we never scored any layers, we don't have a preferred frame rate
+ if (std::all_of(scores.begin(), scores.end(),
+ [](const RefreshRateScore& score) { return score.score == 0; })) {
+ continue;
+ }
+
+ // Now that we scored all the refresh rates we need to pick the one that got the highest
+ // score.
+ const RefreshRate* bestRefreshRate = getBestRefreshRate(scores.begin(), scores.end());
+
+ // If the nest refresh rate is the current one, we don't have an override
+ if (!bestRefreshRate->getFps().equalsWithMargin(displayFrameRate)) {
+ frameRateOverrides.emplace(uid, bestRefreshRate->getFps());
+ }
+ }
+
+ return frameRateOverrides;
+}
+
template <typename Iter>
const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
constexpr auto EPSILON = 0.001f;
- const RefreshRate* bestRefreshRate = begin->first;
- float max = begin->second;
+ const RefreshRate* bestRefreshRate = begin->refreshRate;
+ float max = begin->score;
for (auto i = begin; i != end; ++i) {
const auto [refreshRate, score] = *i;
ALOGV("%s scores %.2f", refreshRate->getName().c_str(), score);
@@ -427,6 +533,7 @@
HwcConfigIndexType currentConfigId)
: mKnownFrameRates(constructKnownFrameRates(configs)) {
LOG_ALWAYS_FATAL_IF(configs.empty());
+ LOG_ALWAYS_FATAL_IF(currentConfigId.value() < 0);
LOG_ALWAYS_FATAL_IF(currentConfigId.value() >= configs.size());
for (auto configId = HwcConfigIndexType(0); configId.value() < configs.size(); configId++) {
@@ -446,6 +553,16 @@
mDisplayManagerPolicy.defaultConfig = currentConfigId;
mMinSupportedRefreshRate = sortedConfigs.front();
mMaxSupportedRefreshRate = sortedConfigs.back();
+
+ mSupportsFrameRateOverride = false;
+ for (const auto& config1 : sortedConfigs) {
+ for (const auto& config2 : sortedConfigs) {
+ if (getFrameRateDivider(config1->getFps(), config2->getFps()) >= 2) {
+ mSupportsFrameRateOverride = true;
+ break;
+ }
+ }
+ }
constructAvailableRefreshRates();
}
@@ -645,50 +762,22 @@
return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
}
-void RefreshRateConfigs::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) {
- if (frameRateOverride.frameRateHz > 0 && frameRateOverride.frameRateHz < 1) {
- return;
- }
-
- std::lock_guard lock(mLock);
- if (frameRateOverride.frameRateHz != 0) {
- mPreferredRefreshRateForUid[frameRateOverride.uid] = Fps(frameRateOverride.frameRateHz);
- } else {
- mPreferredRefreshRateForUid.erase(frameRateOverride.uid);
- }
-}
-
-int RefreshRateConfigs::getRefreshRateDividerForUid(uid_t uid) const {
- std::lock_guard lock(mLock);
-
- const auto iter = mPreferredRefreshRateForUid.find(uid);
- if (iter == mPreferredRefreshRateForUid.end()) {
- return 1;
- }
-
+int RefreshRateConfigs::getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate) {
// This calculation needs to be in sync with the java code
// in DisplayManagerService.getDisplayInfoForFrameRateOverride
constexpr float kThreshold = 0.1f;
- const auto refreshRateHz = iter->second;
- const auto numPeriods = mCurrentRefreshRate->getFps().getValue() / refreshRateHz.getValue();
+ const auto numPeriods = displayFrameRate.getValue() / layerFrameRate.getValue();
const auto numPeriodsRounded = std::round(numPeriods);
if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) {
- return 1;
+ return 0;
}
return static_cast<int>(numPeriodsRounded);
}
-std::vector<FrameRateOverride> RefreshRateConfigs::getFrameRateOverrides() {
+int RefreshRateConfigs::getRefreshRateDivider(Fps frameRate) const {
std::lock_guard lock(mLock);
- std::vector<FrameRateOverride> overrides;
- overrides.reserve(mPreferredRefreshRateForUid.size());
-
- for (const auto [uid, frameRate] : mPreferredRefreshRateForUid) {
- overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
- }
-
- return overrides;
+ return getFrameRateDivider(mCurrentRefreshRate->getFps(), frameRate);
}
void RefreshRateConfigs::dump(std::string& result) const {
@@ -710,7 +799,12 @@
base::StringAppendF(&result, "\t%s\n", refreshRate->toString().c_str());
}
+ base::StringAppendF(&result, "Supports Frame Rate Override: %s\n",
+ mSupportsFrameRateOverride ? "yes" : "no");
result.append("\n");
}
} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 612babf..e4bbf7f 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -221,6 +221,8 @@
struct LayerRequirement {
// Layer's name. Used for debugging purposes.
std::string name;
+ // Layer's owner uid
+ uid_t ownerUid = static_cast<uid_t>(-1);
// Layer vote type.
LayerVoteType vote = LayerVoteType::NoVote;
// Layer's desired refresh rate, if applicable.
@@ -316,18 +318,18 @@
// refresh rates.
KernelIdleTimerAction getIdleTimerAction() const;
- // Stores the preferred refresh rate that an app should run at.
- // FrameRateOverride.refreshRateHz == 0 means no preference.
- void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mLock);
+ bool supportsFrameRateOverride() const { return mSupportsFrameRateOverride; }
// Returns a divider for the current refresh rate
- int getRefreshRateDividerForUid(uid_t) const EXCLUDES(mLock);
+ int getRefreshRateDivider(Fps frameRate) const EXCLUDES(mLock);
+
+ // Returns the frame rate override for each uid
+ using UidToFrameRateOverride = std::map<uid_t, Fps>;
+ UidToFrameRateOverride getFrameRateOverrides(const std::vector<LayerRequirement>& layers,
+ Fps displayFrameRate) const EXCLUDES(mLock);
void dump(std::string& result) const EXCLUDES(mLock);
- // Returns the current frame rate overrides
- std::vector<FrameRateOverride> getFrameRateOverrides() EXCLUDES(mLock);
-
private:
friend class RefreshRateConfigsTest;
@@ -364,6 +366,16 @@
const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
bool isPolicyValid(const Policy& policy);
+ // Return the display refresh rate divider to match the layer
+ // frame rate, or 0 if the display refresh rate is not a multiple of the
+ // layer refresh rate.
+ static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate);
+
+ // calculates a score for a layer. Used to determine the display refresh rate
+ // and the frame rate override for certains applications.
+ float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&,
+ bool isSeamlessSwitch) const REQUIRES(mLock);
+
// The list of refresh rates, indexed by display config ID. This must not change after this
// object is initialized.
AllRefreshRatesMapType mRefreshRates;
@@ -385,10 +397,6 @@
Policy mDisplayManagerPolicy GUARDED_BY(mLock);
std::optional<Policy> mOverridePolicy GUARDED_BY(mLock);
- // A mapping between a UID and a preferred refresh rate that this app would
- // run at.
- std::unordered_map<uid_t, Fps> mPreferredRefreshRateForUid GUARDED_BY(mLock);
-
// The min and max refresh rates supported by the device.
// This will not change at runtime.
const RefreshRate* mMinSupportedRefreshRate;
@@ -399,6 +407,8 @@
// A sorted list of known frame rates that a Heuristic layer will choose
// from based on the closest value.
const std::vector<Fps> mKnownFrameRates;
+
+ bool mSupportsFrameRateOverride;
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index effdbcb..18c899b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -206,8 +206,36 @@
readyDuration, traceVsync, name);
}
+std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
+ std::lock_guard lock(mFrameRateOverridesMutex);
+ {
+ const auto iter = mFrameRateOverridesFromBackdoor.find(uid);
+ if (iter != mFrameRateOverridesFromBackdoor.end()) {
+ return std::make_optional<Fps>(iter->second);
+ }
+ }
+
+ {
+ const auto iter = mFrameRateOverridesByContent.find(uid);
+ if (iter != mFrameRateOverridesByContent.end()) {
+ return std::make_optional<Fps>(iter->second);
+ }
+ }
+
+ return std::nullopt;
+}
+
bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const {
- const auto divider = mRefreshRateConfigs.getRefreshRateDividerForUid(uid);
+ if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
+ return true;
+ }
+
+ const auto frameRate = getFrameRateOverride(uid);
+ if (!frameRate.has_value()) {
+ return true;
+ }
+
+ const auto divider = mRefreshRateConfigs.getRefreshRateDivider(*frameRate);
if (divider <= 1) {
return true;
}
@@ -215,14 +243,22 @@
return mVsyncSchedule.tracker->isVSyncInPhase(expectedVsyncTimestamp, divider);
}
+impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const {
+ if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
+ return {};
+ }
+
+ return [this](nsecs_t expectedVsyncTimestamp, uid_t uid) {
+ return !isVsyncValid(expectedVsyncTimestamp, uid);
+ };
+}
+
Scheduler::ConnectionHandle Scheduler::createConnection(
const char* connectionName, frametimeline::TokenManager* tokenManager,
std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration);
- auto throttleVsync = [this](nsecs_t expectedVsyncTimestamp, uid_t uid) {
- return !isVsyncValid(expectedVsyncTimestamp, uid);
- };
+ auto throttleVsync = makeThrottleVsyncCallback();
auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource), tokenManager,
std::move(interceptCallback),
std::move(throttleVsync));
@@ -290,11 +326,22 @@
thread->onScreenReleased();
}
-void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- std::vector<FrameRateOverride> overrides) {
+void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) {
+ std::vector<FrameRateOverride> overrides;
+ {
+ std::lock_guard lock(mFrameRateOverridesMutex);
+ for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) {
+ overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
+ }
+ for (const auto& [uid, frameRate] : mFrameRateOverridesByContent) {
+ if (mFrameRateOverridesFromBackdoor.count(uid) == 0) {
+ overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
+ }
+ }
+ }
android::EventThread* thread;
{
- std::lock_guard<std::mutex> lock(mConnectionsLock);
+ std::lock_guard lock(mConnectionsLock);
RETURN_IF_INVALID_HANDLE(handle);
thread = mConnections[handle].thread.get();
}
@@ -303,9 +350,11 @@
void Scheduler::onPrimaryDisplayConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
- std::lock_guard<std::mutex> lock(mFeatureStateLock);
- // Cache the last reported config for primary display.
- mFeatures.cachedConfigChangedParams = {handle, displayId, configId, vsyncPeriod};
+ {
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ // Cache the last reported config for primary display.
+ mFeatures.cachedConfigChangedParams = {handle, displayId, configId, vsyncPeriod};
+ }
onNonPrimaryDisplayConfigChanged(handle, displayId, configId, vsyncPeriod);
}
@@ -377,9 +426,10 @@
thread->setDuration(workDuration, readyDuration);
}
-void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats, nsecs_t now) {
- stats->vsyncTime = mVsyncSchedule.tracker->nextAnticipatedVSyncTimeFrom(now);
- stats->vsyncPeriod = mVsyncSchedule.tracker->currentPeriod();
+DisplayStatInfo Scheduler::getDisplayStatInfo(nsecs_t now) {
+ const auto vsyncTime = mVsyncSchedule.tracker->nextAnticipatedVSyncTimeFrom(now);
+ const auto vsyncPeriod = mVsyncSchedule.tracker->currentPeriod();
+ return DisplayStatInfo{.vsyncTime = vsyncTime, .vsyncPeriod = vsyncPeriod};
}
Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) {
@@ -550,7 +600,10 @@
ATRACE_CALL();
scheduler::LayerHistory::Summary summary = mLayerHistory->summarize(systemTime());
+ scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
HwcConfigIndexType newConfigId;
+ bool frameRateChanged;
+ bool frameRateOverridesChanged;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
if (mFeatures.contentRequirements == summary) {
@@ -558,22 +611,32 @@
}
mFeatures.contentRequirements = summary;
- scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
newConfigId = calculateRefreshRateConfigIndexType(&consideredSignals);
+ auto& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+ frameRateOverridesChanged =
+ updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps());
+
if (mFeatures.configId == newConfigId) {
// We don't need to change the config, but we might need to send an event
// about a config change, since it was suppressed due to a previous idleConsidered
if (!consideredSignals.idle) {
dispatchCachedReportedConfig();
}
- return;
+ frameRateChanged = false;
+ } else {
+ mFeatures.configId = newConfigId;
+ frameRateChanged = true;
}
- mFeatures.configId = newConfigId;
+ }
+ if (frameRateChanged) {
auto& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
mSchedulerCallback.changeRefreshRate(newRefreshRate,
consideredSignals.idle ? ConfigEvent::None
: ConfigEvent::Changed);
}
+ if (frameRateOverridesChanged) {
+ mSchedulerCallback.triggerOnFrameRateOverridesChanged();
+ }
}
void Scheduler::resetIdleTimer() {
@@ -666,6 +729,21 @@
StringAppendF(&result, "+ Content detection: %s %s\n\n",
toContentDetectionString(mOptions.useContentDetection),
mLayerHistory ? mLayerHistory->dump().c_str() : "(no layer history)");
+
+ {
+ std::lock_guard lock(mFrameRateOverridesMutex);
+ StringAppendF(&result, "Frame Rate Overrides (backdoor): {");
+ for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) {
+ StringAppendF(&result, "[uid: %d frameRate: %s], ", uid, to_string(frameRate).c_str());
+ }
+ StringAppendF(&result, "}\n");
+
+ StringAppendF(&result, "Frame Rate Overrides (setFrameRate): {");
+ for (const auto& [uid, frameRate] : mFrameRateOverridesByContent) {
+ StringAppendF(&result, "[uid: %d frameRate: %s], ", uid, to_string(frameRate).c_str());
+ }
+ StringAppendF(&result, "}\n");
+ }
}
void Scheduler::dumpVsync(std::string& s) const {
@@ -677,9 +755,41 @@
mVsyncSchedule.dispatch->dump(s);
}
+bool Scheduler::updateFrameRateOverrides(
+ scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, Fps displayRefreshRate) {
+ if (!mRefreshRateConfigs.supportsFrameRateOverride()) {
+ return false;
+ }
+
+ if (consideredSignals.touch) {
+ std::lock_guard lock(mFrameRateOverridesMutex);
+ const bool changed = !mFrameRateOverridesByContent.empty();
+ mFrameRateOverridesByContent.clear();
+ return changed;
+ }
+
+ if (!consideredSignals.idle) {
+ const auto frameRateOverrides =
+ mRefreshRateConfigs.getFrameRateOverrides(mFeatures.contentRequirements,
+ displayRefreshRate);
+ std::lock_guard lock(mFrameRateOverridesMutex);
+ if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(),
+ frameRateOverrides.begin(), frameRateOverrides.end(),
+ [](const std::pair<uid_t, Fps>& a, const std::pair<uid_t, Fps>& b) {
+ return a.first == b.first && a.second.equalsWithMargin(b.second);
+ })) {
+ mFrameRateOverridesByContent = frameRateOverrides;
+ return true;
+ }
+ }
+ return false;
+}
+
template <class T>
bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
HwcConfigIndexType newConfigId;
+ bool refreshRateChanged = false;
+ bool frameRateOverridesChanged;
scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
@@ -688,20 +798,32 @@
}
*currentState = newState;
newConfigId = calculateRefreshRateConfigIndexType(&consideredSignals);
+ const RefreshRate& newRefreshRate =
+ mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+ frameRateOverridesChanged =
+ updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps());
if (mFeatures.configId == newConfigId) {
// We don't need to change the config, but we might need to send an event
// about a config change, since it was suppressed due to a previous idleConsidered
if (!consideredSignals.idle) {
dispatchCachedReportedConfig();
}
- return consideredSignals.touch;
+ } else {
+ mFeatures.configId = newConfigId;
+ refreshRateChanged = true;
}
- mFeatures.configId = newConfigId;
}
- const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
- mSchedulerCallback.changeRefreshRate(newRefreshRate,
- consideredSignals.idle ? ConfigEvent::None
- : ConfigEvent::Changed);
+ if (refreshRateChanged) {
+ const RefreshRate& newRefreshRate =
+ mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+
+ mSchedulerCallback.changeRefreshRate(newRefreshRate,
+ consideredSignals.idle ? ConfigEvent::None
+ : ConfigEvent::Changed);
+ }
+ if (frameRateOverridesChanged) {
+ mSchedulerCallback.triggerOnFrameRateOverridesChanged();
+ }
return consideredSignals.touch;
}
@@ -775,4 +897,17 @@
}
}
+void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) {
+ if (frameRateOverride.frameRateHz > 0.f && frameRateOverride.frameRateHz < 1.f) {
+ return;
+ }
+
+ std::lock_guard lock(mFrameRateOverridesMutex);
+ if (frameRateOverride.frameRateHz != 0.f) {
+ mFrameRateOverridesFromBackdoor[frameRateOverride.uid] = Fps(frameRateOverride.frameRateHz);
+ } else {
+ mFrameRateOverridesFromBackdoor.erase(frameRateOverride.uid);
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index f16e1f9..cae3fe7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -26,8 +26,9 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <ui/GraphicTypes.h>
-#pragma clang diagnostic pop
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
#include "EventThread.h"
#include "LayerHistory.h"
@@ -60,6 +61,7 @@
scheduler::RefreshRateConfigEvent) = 0;
virtual void repaintEverythingForHWC() = 0;
virtual void kernelTimerChanged(bool expired) = 0;
+ virtual void triggerOnFrameRateOverridesChanged() = 0;
protected:
~ISchedulerCallback() = default;
@@ -93,14 +95,14 @@
void onScreenAcquired(ConnectionHandle);
void onScreenReleased(ConnectionHandle);
- void onFrameRateOverridesChanged(ConnectionHandle, PhysicalDisplayId,
- std::vector<FrameRateOverride>);
+ void onFrameRateOverridesChanged(ConnectionHandle, PhysicalDisplayId)
+ EXCLUDES(mFrameRateOverridesMutex) EXCLUDES(mConnectionsLock);
// Modifies work duration in the event thread.
void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration);
- void getDisplayStatInfo(DisplayStatInfo* stats, nsecs_t now);
+ DisplayStatInfo getDisplayStatInfo(nsecs_t now);
// Returns injector handle if injection has toggled, or an invalid handle otherwise.
ConnectionHandle enableVSyncInjection(bool enable);
@@ -144,7 +146,8 @@
// Returns true if a given vsync timestamp is considered valid vsync
// for a given uid
- bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const;
+ bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const
+ EXCLUDES(mFrameRateOverridesMutex);
void dump(std::string&) const;
void dump(ConnectionHandle, std::string&) const;
@@ -169,6 +172,10 @@
std::chrono::nanoseconds readyDuration,
bool traceVsync = true);
+ // Stores the preferred refresh rate that an app should run at.
+ // FrameRateOverride.refreshRateHz == 0 means no preference.
+ void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesMutex);
+
private:
friend class TestableScheduler;
@@ -226,6 +233,12 @@
REQUIRES(mFeatureStateLock);
void dispatchCachedReportedConfig() REQUIRES(mFeatureStateLock);
+ bool updateFrameRateOverrides(scheduler::RefreshRateConfigs::GlobalSignals consideredSignals,
+ Fps displayRefreshRate) REQUIRES(mFeatureStateLock)
+ EXCLUDES(mFrameRateOverridesMutex);
+
+ std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex);
+ impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const;
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
struct Connection {
@@ -264,7 +277,7 @@
// In order to make sure that the features don't override themselves, we need a state machine
// to keep track which feature requested the config change.
- std::mutex mFeatureStateLock;
+ mutable std::mutex mFeatureStateLock;
struct {
TimerState idleTimer = TimerState::Reset;
@@ -295,6 +308,17 @@
static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms;
const std::unique_ptr<PredictedVsyncTracer> mPredictedVsyncTracer;
+
+ // The frame rate override lists need their own mutex as they are being read
+ // by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks
+ mutable std::mutex mFrameRateOverridesMutex;
+
+ // mappings between a UID and a preferred refresh rate that this app would
+ // run at.
+ scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent
+ GUARDED_BY(mFrameRateOverridesMutex);
+ scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor
+ GUARDED_BY(mFrameRateOverridesMutex);
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index a6f9372..7cca206 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
#include "VSyncPredictor.h"
@@ -339,3 +343,5 @@
} // namespace android::scheduler
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f1306e7..6967f69 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -963,7 +964,7 @@
return BAD_VALUE;
}
- mScheduler->getDisplayStatInfo(stats, systemTime());
+ *stats = mScheduler->getDisplayStatInfo(systemTime());
return NO_ERROR;
}
@@ -1440,7 +1441,8 @@
status_t SurfaceFlinger::injectVSync(nsecs_t when) {
Mutex::Autolock lock(mStateLock);
- const auto expectedPresent = calculateExpectedPresentTime(when);
+ const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(when);
+ const auto expectedPresent = calculateExpectedPresentTime(stats);
return mScheduler->injectVSync(when, /*expectedVSyncTime=*/expectedPresent,
/*deadlineTimestamp=*/expectedPresent)
? NO_ERROR
@@ -1719,9 +1721,7 @@
return fence->getSignalTime();
}
-nsecs_t SurfaceFlinger::calculateExpectedPresentTime(nsecs_t now) const {
- DisplayStatInfo stats;
- mScheduler->getDisplayStatInfo(&stats, now);
+nsecs_t SurfaceFlinger::calculateExpectedPresentTime(DisplayStatInfo stats) const {
// Inflate the expected present time if we're targetting the next vsync.
return mVsyncModulator->getVsyncConfig().sfOffset > 0 ? stats.vsyncTime
: stats.vsyncTime + stats.vsyncPeriod;
@@ -1769,8 +1769,7 @@
// Add some slop to correct for drift. This should generally be
// smaller than a typical frame duration, but should not be so small
// that it reports reasonable drift as a missed frame.
- DisplayStatInfo stats;
- mScheduler->getDisplayStatInfo(&stats, systemTime());
+ const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(systemTime());
const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2;
const nsecs_t previousPresentTime = previousFramePresentTime();
const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed",
@@ -2147,8 +2146,7 @@
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]);
getBE().mDisplayTimeline.push(presentFenceTime);
- DisplayStatInfo stats;
- mScheduler->getDisplayStatInfo(&stats, systemTime());
+ const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(systemTime());
// We use the CompositionEngine::getLastFrameRefreshTimestamp() which might
// be sampled a little later than when we started doing work for this frame,
@@ -2890,12 +2888,21 @@
Scheduler::ConfigEvent event) {
// If this is called from the main thread mStateLock must be locked before
// Currently the only way to call this function from the main thread is from
- // Sheduler::chooseRefreshRateForContent
+ // Scheduler::chooseRefreshRateForContent
ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
changeRefreshRateLocked(refreshRate, event);
}
+void SurfaceFlinger::triggerOnFrameRateOverridesChanged() {
+ PhysicalDisplayId displayId = [&]() {
+ ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+ return getDefaultDisplayDeviceLocked()->getPhysicalId();
+ }();
+
+ mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
+}
+
void SurfaceFlinger::initScheduler(PhysicalDisplayId primaryDisplayId) {
if (mScheduler) {
// In practice it's not allowed to hotplug in/out the primary display once it's been
@@ -3353,11 +3360,16 @@
const bool pendingTransactions = itr != mTransactionQueues.end();
// Expected present time is computed and cached on invalidate, so it may be stale.
if (!pendingTransactions) {
+ const auto now = systemTime();
+ const bool nextVsyncPending = now < mExpectedPresentTime.load();
+ const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now);
+ mExpectedPresentTime = calculateExpectedPresentTime(stats);
// The transaction might arrive just before the next vsync but after
// invalidate was called. In that case we need to get the next vsync
// afterwards.
- const auto referenceTime = std::max(mExpectedPresentTime.load(), systemTime());
- mExpectedPresentTime = calculateExpectedPresentTime(referenceTime);
+ if (nextVsyncPending) {
+ mExpectedPresentTime += stats.vsyncPeriod;
+ }
}
IPCThreadState* ipc = IPCThreadState::self();
@@ -5364,11 +5376,8 @@
auto inUid = static_cast<uid_t>(data.readInt32());
const auto refreshRate = data.readFloat();
- mRefreshRateConfigs->setPreferredRefreshRateForUid(
- FrameRateOverride{inUid, refreshRate});
- const auto mappings = mRefreshRateConfigs->getFrameRateOverrides();
- mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId,
- std::move(mappings));
+ mScheduler->setPreferredRefreshRateForUid(FrameRateOverride{inUid, refreshRate});
+ mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
return NO_ERROR;
}
}
@@ -6393,4 +6402,4 @@
#endif
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0111acc..9f0f2ea 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -644,6 +644,8 @@
void repaintEverythingForHWC() override;
// Called when kernel idle timer has expired. Used to update the refresh rate overlay.
void kernelTimerChanged(bool expired) override;
+ // Called when the frame rate override list changed to trigger an event.
+ void triggerOnFrameRateOverridesChanged() override;
// Toggles the kernel idle timer on or off depending the policy decisions around refresh rates.
void toggleKernelIdleTimer();
// Keeps track of whether the kernel idle timer is currently enabled, so we don't have to
@@ -863,26 +865,12 @@
/*
* H/W composer
*/
-
- // The current hardware composer interface.
- //
- // The following thread safety rules apply when accessing mHwc, either
- // directly or via getHwComposer():
- //
- // 1. When recreating mHwc, acquire mStateLock. Recreating mHwc must only be
- // done on the main thread.
- //
- // 2. When accessing mHwc on the main thread, it's not necessary to acquire
- // mStateLock.
- //
- // 3. When accessing mHwc on a thread other than the main thread, we always
+ // The following thread safety rules apply when accessing HWComposer:
+ // 1. When reading display state from HWComposer on the main thread, it's not necessary to
+ // acquire mStateLock.
+ // 2. When accessing HWComposer on a thread other than the main thread, we always
// need to acquire mStateLock. This is because the main thread could be
- // in the process of destroying the current mHwc instance.
- //
- // The above thread safety rules only apply to SurfaceFlinger.cpp. In
- // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never
- // destroy it, so it's always safe to access mHwc from any thread without
- // acquiring mStateLock.
+ // in the process of writing display state, e.g. creating or destroying a display.
HWComposer& getHwComposer() const;
/*
@@ -948,7 +936,7 @@
// Calculates the expected present time for this frame. For negative offsets, performs a
// correction using the predicted vsync for the next frame instead.
- nsecs_t calculateExpectedPresentTime(nsecs_t now) const;
+ nsecs_t calculateExpectedPresentTime(DisplayStatInfo) const;
/*
* Display identification
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index a83b2bf..8fac8e9 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -20,11 +20,12 @@
#include <cstdint>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
#include <stats_event.h>
#include <stats_pull_atom_callback.h>
diff --git a/services/surfaceflinger/tests/DetachChildren_test.cpp b/services/surfaceflinger/tests/DetachChildren_test.cpp
index 9c7b1fc..abf8b1a 100644
--- a/services/surfaceflinger/tests/DetachChildren_test.cpp
+++ b/services/surfaceflinger/tests/DetachChildren_test.cpp
@@ -371,4 +371,7 @@
}
}
-} // namespace android
\ No newline at end of file
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 3a8b40f..55b3173 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#include <gtest/gtest.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
@@ -143,3 +147,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index 152d2d2..58b039e 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -70,3 +70,6 @@
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index b87c734..6758518 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -19,6 +19,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <gtest/gtest.h>
#include <gui/ISurfaceComposer.h>
@@ -306,4 +307,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 7df3711..214a0cd 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -837,3 +837,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 81e648a..8dc9a12 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -1043,4 +1044,4 @@
}
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index a24aeba..bd49728 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
// #define LOG_NDEBUG 0
#undef LOG_TAG
@@ -2017,4 +2018,4 @@
}
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp
index 1b8c76d..6bc2318 100644
--- a/services/surfaceflinger/tests/unittests/CachingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#undef LOG_TAG
#define LOG_TAG "CachingTest"
@@ -97,4 +98,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index be9d336..83e3ba4 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#undef LOG_TAG
#define LOG_TAG "CompositionTest"
@@ -1533,4 +1534,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp
index be7609a..77a3e14 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#include <gtest/gtest.h>
#include <vector>
@@ -80,3 +84,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index 02ce079..dc04b6d 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#include <functional>
#include <string_view>
@@ -409,3 +413,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 01cdb28..9ec2d16 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -19,6 +19,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <type_traits>
#include "DisplayIdentificationTest.h"
@@ -364,7 +365,7 @@
static constexpr DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
// The HWC active configuration id
- static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
+ static constexpr hal::HWConfigId HWC_ACTIVE_CONFIG_ID = 2001;
static constexpr PowerMode INIT_POWER_MODE = hal::PowerMode::ON;
static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) {
@@ -415,6 +416,45 @@
ceDisplayArgs);
}
+ static void setupHwcGetConfigsCallExpectations(DisplayTransactionTest* test) {
+ if (HWC_DISPLAY_TYPE == DisplayType::PHYSICAL) {
+ EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(std::vector<hal::HWConfigId>{
+ HWC_ACTIVE_CONFIG_ID}),
+ Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::WIDTH, _))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::HEIGHT, _))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::VSYNC_PERIOD, _))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::DPI_X, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::DPI_Y, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::CONFIG_GROUP, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
+ } else {
+ EXPECT_CALL(*test->mComposer, getDisplayConfigs(_, _)).Times(0);
+ EXPECT_CALL(*test->mComposer, getDisplayAttribute(_, _, _, _)).Times(0);
+ }
+ }
+
static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
constexpr auto CONNECTION_TYPE =
PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
@@ -426,33 +466,8 @@
EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_))
.WillOnce(Return(hal::Error::NONE));
- EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
- Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::WIDTH, _))
- .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::HEIGHT, _))
- .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::VSYNC_PERIOD, _))
- .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::DPI_X, _))
- .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::DPI_Y, _))
- .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
- IComposerClient::Attribute::CONFIG_GROUP, _))
- .WillOnce(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
+
+ setupHwcGetConfigsCallExpectations(test);
if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
@@ -559,6 +574,11 @@
ceDisplayArgs);
}
+ static void setupHwcGetConfigsCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getDisplayConfigs(_, _)).Times(0);
+ EXPECT_CALL(*test->mComposer, getDisplayAttribute(_, _, _, _)).Times(0);
+ }
+
static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
}
@@ -753,4 +773,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index ee56178..0cd50ce 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
@@ -623,3 +627,6 @@
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 4b897fa..169698b 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#include "gmock/gmock-spec-builders.h"
#include "mock/MockTimeStats.h"
#undef LOG_TAG
@@ -1333,3 +1337,6 @@
JankType::AppDeadlineMissed | JankType::BufferStuffing);
}
} // namespace android::frametimeline
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
index a119e27..2c71a2e 100644
--- a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
@@ -381,4 +382,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index fa12315..bc1e88a 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -42,7 +42,10 @@
namespace android {
namespace {
-namespace hal = android::hardware::graphics::composer::hal;
+namespace V2_1 = hardware::graphics::composer::V2_1;
+namespace V2_4 = hardware::graphics::composer::V2_4;
+
+using Hwc2::Config;
using ::testing::_;
using ::testing::DoAll;
@@ -170,5 +173,88 @@
EXPECT_EQ(hal::Error::UNSUPPORTED, result);
}
+class HWComposerConfigsTest : public testing::Test {
+public:
+ Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>();
+ MockHWC2ComposerCallback mCallback;
+
+ void setActiveConfig(Config config) {
+ EXPECT_CALL(*mHal, getActiveConfig(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(config), Return(V2_1::Error::NONE)));
+ }
+
+ void setDisplayConfigs(std::vector<Config> configs) {
+ EXPECT_CALL(*mHal, getDisplayConfigs(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(configs), Return(V2_1::Error::NONE)));
+ EXPECT_CALL(*mHal, getDisplayAttribute(_, _, _, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(1), Return(V2_1::Error::NONE)));
+ }
+
+ void testSetActiveConfigWithConstraintsCommon(bool isVsyncPeriodSwitchSupported);
+};
+
+void HWComposerConfigsTest::testSetActiveConfigWithConstraintsCommon(
+ bool isVsyncPeriodSwitchSupported) {
+ EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
+ EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
+ EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_)).WillOnce(Return(V2_4::Error::UNSUPPORTED));
+ EXPECT_CALL(*mHal, registerCallback(_));
+ EXPECT_CALL(*mHal, setVsyncEnabled(_, _)).WillRepeatedly(Return(V2_1::Error::NONE));
+ EXPECT_CALL(*mHal, getDisplayIdentificationData(_, _, _))
+ .WillRepeatedly(Return(V2_1::Error::UNSUPPORTED));
+ EXPECT_CALL(*mHal, setClientTargetSlotCount(_)).WillRepeatedly(Return(V2_1::Error::NONE));
+
+ EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported())
+ .WillRepeatedly(Return(isVsyncPeriodSwitchSupported));
+
+ if (isVsyncPeriodSwitchSupported) {
+ EXPECT_CALL(*mHal, setActiveConfigWithConstraints(_, _, _, _))
+ .WillRepeatedly(Return(V2_4::Error::NONE));
+ } else {
+ EXPECT_CALL(*mHal, setActiveConfig(_, _)).WillRepeatedly(Return(V2_1::Error::NONE));
+ }
+
+ impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
+ hwc.setConfiguration(&mCallback, 123);
+
+ setDisplayConfigs({15});
+ setActiveConfig(15);
+
+ const auto physicalId = PhysicalDisplayId::fromPort(0);
+ const hal::HWDisplayId hwcId = 0;
+ hwc.allocatePhysicalDisplay(hwcId, physicalId);
+
+ hal::VsyncPeriodChangeConstraints constraints;
+ constraints.desiredTimeNanos = systemTime();
+ constraints.seamlessRequired = false;
+
+ hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
+ constexpr size_t kConfigIndex = 0;
+ const auto status =
+ hwc.setActiveConfigWithConstraints(physicalId, kConfigIndex, constraints, &timeline);
+ EXPECT_EQ(NO_ERROR, status);
+
+ const std::vector<Config> kConfigs{7, 8, 9, 10, 11};
+ // Change the set of supported modes.
+ setDisplayConfigs(kConfigs);
+ setActiveConfig(11);
+ hwc.onHotplug(hwcId, hal::Connection::CONNECTED);
+ hwc.allocatePhysicalDisplay(hwcId, physicalId);
+
+ for (size_t configIndex = 0; configIndex < kConfigs.size(); configIndex++) {
+ const auto status =
+ hwc.setActiveConfigWithConstraints(physicalId, configIndex, constraints, &timeline);
+ EXPECT_EQ(NO_ERROR, status) << "Error when switching to config " << configIndex;
+ }
+}
+
+TEST_F(HWComposerConfigsTest, setActiveConfigWithConstraintsWithVsyncSwitchingSupported) {
+ testSetActiveConfigWithConstraintsCommon(/*supported=*/true);
+}
+
+TEST_F(HWComposerConfigsTest, setActiveConfigWithConstraintsWithVsyncSwitchingNotSupported) {
+ testSetActiveConfigWithConstraintsCommon(/*supported=*/false);
+}
+
} // namespace
-} // namespace android
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index cbc1e02..2ee9c64 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#undef LOG_TAG
#define LOG_TAG "LayerHistoryTest"
@@ -754,3 +758,6 @@
} // namespace
} // namespace scheduler
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
index 75a061b..373fd74 100644
--- a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
@@ -107,3 +111,6 @@
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 83ad737..45f0ee6 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -1545,40 +1549,117 @@
EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
}
-TEST_F(RefreshRateConfigsTest, RefreshRateDividerForUnknownUid) {
- auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
- /*currentConfigId=*/HWC_CONFIG_ID_30);
- EXPECT_EQ(1, refreshRateConfigs->getRefreshRateDividerForUid(1234));
-}
-
TEST_F(RefreshRateConfigsTest, RefreshRateDividerForUid) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
/*currentConfigId=*/HWC_CONFIG_ID_30);
- const uid_t uid = 1234;
- refreshRateConfigs->setPreferredRefreshRateForUid({uid, 30});
- EXPECT_EQ(1, refreshRateConfigs->getRefreshRateDividerForUid(uid));
+
+ const auto frameRate = Fps(30.f);
+ EXPECT_EQ(1, refreshRateConfigs->getRefreshRateDivider(frameRate));
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_60);
- EXPECT_EQ(2, refreshRateConfigs->getRefreshRateDividerForUid(uid));
+ EXPECT_EQ(2, refreshRateConfigs->getRefreshRateDivider(frameRate));
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_72);
- EXPECT_EQ(1, refreshRateConfigs->getRefreshRateDividerForUid(uid));
+ EXPECT_EQ(0, refreshRateConfigs->getRefreshRateDivider(frameRate));
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
- EXPECT_EQ(3, refreshRateConfigs->getRefreshRateDividerForUid(uid));
+ EXPECT_EQ(3, refreshRateConfigs->getRefreshRateDivider(frameRate));
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_120);
- EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDividerForUid(uid));
+ EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDivider(frameRate));
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
- refreshRateConfigs->setPreferredRefreshRateForUid({uid, 22.5f});
- EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDividerForUid(uid));
- refreshRateConfigs->setPreferredRefreshRateForUid({uid, 22.6f});
- EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDividerForUid(uid));
+ EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDivider(Fps(22.5f)));
+ EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDivider(Fps(22.6f)));
+}
+
+TEST_F(RefreshRateConfigsTest, populatePreferredFrameRate_noLayers) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
+ HWC_CONFIG_ID_120);
+
+ auto layers = std::vector<LayerRequirement>{};
+ ASSERT_TRUE(refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f)).empty());
+}
+
+TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_60on120) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
+ HWC_CONFIG_ID_120);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ layers[0].name = "Test layer";
+ layers[0].ownerUid = 1234;
+ layers[0].desiredRefreshRate = Fps(60.0f);
+ layers[0].vote = LayerVoteType::ExplicitDefault;
+ auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ ASSERT_EQ(1, frameRateOverrides.size());
+ ASSERT_EQ(1, frameRateOverrides.count(1234));
+ ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+
+ layers[0].vote = LayerVoteType::ExplicitExactOrMultiple;
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ ASSERT_EQ(1, frameRateOverrides.size());
+ ASSERT_EQ(1, frameRateOverrides.count(1234));
+ ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+
+ layers[0].vote = LayerVoteType::NoVote;
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ ASSERT_TRUE(frameRateOverrides.empty());
+
+ layers[0].vote = LayerVoteType::Min;
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ ASSERT_TRUE(frameRateOverrides.empty());
+
+ layers[0].vote = LayerVoteType::Max;
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ ASSERT_TRUE(frameRateOverrides.empty());
+
+ layers[0].vote = LayerVoteType::Heuristic;
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ ASSERT_TRUE(frameRateOverrides.empty());
+}
+
+TEST_F(RefreshRateConfigsTest, populatePreferredFrameRate_twoUids) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
+ HWC_CONFIG_ID_120);
+
+ auto layers = std::vector<LayerRequirement>{
+ LayerRequirement{.ownerUid = 1234, .weight = 1.0f},
+ LayerRequirement{.ownerUid = 5678, .weight = 1.0f},
+ };
+
+ layers[0].name = "Test layer 1234";
+ layers[0].desiredRefreshRate = Fps(60.0f);
+ layers[0].vote = LayerVoteType::ExplicitDefault;
+
+ layers[1].name = "Test layer 5678";
+ layers[1].desiredRefreshRate = Fps(30.0f);
+ layers[1].vote = LayerVoteType::ExplicitDefault;
+ auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+
+ ASSERT_EQ(2, frameRateOverrides.size());
+ ASSERT_EQ(1, frameRateOverrides.count(1234));
+ ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+ ASSERT_EQ(1, frameRateOverrides.count(5678));
+ ASSERT_EQ(30.0f, frameRateOverrides.at(5678).getValue());
+
+ layers[1].vote = LayerVoteType::Heuristic;
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ ASSERT_EQ(1, frameRateOverrides.size());
+ ASSERT_EQ(1, frameRateOverrides.count(1234));
+ ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue());
+
+ layers[1].ownerUid = 1234;
+ frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f));
+ ASSERT_TRUE(frameRateOverrides.empty());
}
} // namespace
} // namespace scheduler
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index e93d0d0..2188402 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -216,3 +220,6 @@
} // namespace
} // namespace scheduler
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
index cd3f6ab..65efc85 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
@@ -144,7 +144,7 @@
// SF should have a display token.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
+ ASSERT_EQ(mFlinger.mutablePhysicalDisplayTokens().count(displayId), 1);
auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId];
verifyDisplayIsConnected<Case>(displayToken);
@@ -259,14 +259,6 @@
processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest,
- processesHotplugConnectPrimaryDisplayWithExternalAlreadyConnected) {
- // Inject an external display.
- ExternalDisplayVariant::injectHwcDisplay(this);
-
- processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
-}
-
TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) {
// Inject a primary display.
PrimaryDisplayVariant::injectHwcDisplay(this);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 61f0788..cedb404 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -223,6 +223,7 @@
// Various native window calls will be made.
Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+ Case::Display::setupHwcGetConfigsCallExpectations(this);
Case::WideColorSupport::setupComposerCallExpectations(this);
Case::HdrSupport::setupComposerCallExpectations(this);
Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
@@ -236,6 +237,7 @@
ASSERT_TRUE(displayId);
const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
ASSERT_TRUE(hwcDisplayId);
+ mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId);
state.physical = {.id = *displayId, .type = *connectionType, .hwcDisplayId = *hwcDisplayId};
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9224c1b..b57d473 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -561,8 +561,15 @@
const auto physicalId = PhysicalDisplayId::tryCast(mDisplayId);
LOG_ALWAYS_FATAL_IF(!physicalId);
flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, *physicalId);
- (mIsPrimary ? flinger->mutableInternalHwcDisplayId()
- : flinger->mutableExternalHwcDisplayId()) = mHwcDisplayId;
+ if (mIsPrimary) {
+ flinger->mutableInternalHwcDisplayId() = mHwcDisplayId;
+ } else {
+ // If there is an external HWC display there should always be an internal ID
+ // as well. Set it to some arbitrary value.
+ auto& internalId = flinger->mutableInternalHwcDisplayId();
+ if (!internalId) internalId = mHwcDisplayId - 1;
+ flinger->mutableExternalHwcDisplayId() = mHwcDisplayId;
+ }
}
}
@@ -691,6 +698,7 @@
void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ConfigEvent) override {}
void repaintEverythingForHWC() override {}
void kernelTimerChanged(bool) override {}
+ void triggerOnFrameRateOverridesChanged() {}
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index ace370f..fb9afd4 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
@@ -1320,4 +1321,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index fa6ff30..06275c6 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#undef LOG_TAG
#define LOG_TAG "CompositionTest"
@@ -344,4 +345,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 72b5396..00cf574 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
@@ -1152,4 +1153,4 @@
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index a142022..a4ddbf4 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -17,6 +17,7 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
@@ -492,4 +493,4 @@
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index a7568e4..b9651ea 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wextra"
+
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
#define LOG_NDEBUG 0
@@ -491,3 +495,6 @@
}
} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 078d8e07..ba2e4db 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -33,6 +33,7 @@
MOCK_CONST_METHOD0(isVisible, bool());
MOCK_METHOD0(createClone, sp<Layer>());
MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
+ MOCK_CONST_METHOD0(getOwnerUid, uid_t());
};
} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index 72bc89c..ab19886 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -29,6 +29,7 @@
scheduler::RefreshRateConfigEvent));
MOCK_METHOD0(repaintEverythingForHWC, void());
MOCK_METHOD1(kernelTimerChanged, void(bool));
+ MOCK_METHOD0(triggerOnFrameRateOverridesChanged, void());
};
struct NoOpSchedulerCallback final : ISchedulerCallback {
@@ -37,6 +38,7 @@
scheduler::RefreshRateConfigEvent) override {}
void repaintEverythingForHWC() override {}
void kernelTimerChanged(bool) override {}
+ void triggerOnFrameRateOverridesChanged() {}
};
} // namespace android::mock
diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h
index 5c5b18e..3cbfed9 100644
--- a/services/surfaceflinger/tests/utils/TransactionUtils.h
+++ b/services/surfaceflinger/tests/utils/TransactionUtils.h
@@ -18,6 +18,7 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wextra"
#include <chrono>
@@ -186,4 +187,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
\ No newline at end of file