Merge "Add all SF tests to presubmit, excluding failing tests"
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index ca9c608..aeca12b 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -123,13 +123,10 @@
const std::unique_ptr<String16>& featureId, const String16& message) {
sp<IAppOpsService> service = getService();
int32_t mode = service != nullptr
- ? service->noteOperation(op, uid, callingPackage, featureId)
+ ? service->noteOperation(op, uid, callingPackage, featureId, shouldCollectNotes(op),
+ message)
: APP_OPS_MANAGER_UNAVAILABLE_MODE;
- if (mode == AppOpsManager::MODE_ALLOWED) {
- markAppOpNoted(uid, callingPackage, op, featureId, message);
- }
-
return mode;
}
@@ -145,11 +142,8 @@
sp<IAppOpsService> service = getService();
int32_t mode = service != nullptr
? service->startOperation(getClientId(), op, uid, callingPackage,
- featureId, startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
-
- if (mode == AppOpsManager::MODE_ALLOWED) {
- markAppOpNoted(uid, callingPackage, op, featureId, message);
- }
+ featureId, startIfModeDefault, shouldCollectNotes(op), message)
+ : APP_OPS_MANAGER_UNAVAILABLE_MODE;
return mode;
}
@@ -196,40 +190,17 @@
}
}
+// check it the appops needs to be collected and cache result
bool AppOpsManager::shouldCollectNotes(int32_t opcode) {
- sp<IAppOpsService> service = getService();
- if (service != nullptr) {
- return service->shouldCollectNotes(opcode);
- }
- return false;
-}
-
-void AppOpsManager::markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
- const std::unique_ptr<String16>& featureId, const String16& message) {
- // check it the appops needs to be collected and cache result
- if (appOpsToNote[opCode] == 0) {
- if (shouldCollectNotes(opCode)) {
- appOpsToNote[opCode] = 2;
+ if (appOpsToNote[opcode] == 0) {
+ if (getService()->shouldCollectNotes(opcode)) {
+ appOpsToNote[opcode] = 2;
} else {
- appOpsToNote[opCode] = 1;
+ appOpsToNote[opcode] = 1;
}
}
- if (appOpsToNote[opCode] != 2) {
- return;
- }
-
- noteAsyncOp(std::unique_ptr<String16>(), uid, packageName, opCode, featureId, message);
-}
-
-void AppOpsManager::noteAsyncOp(const std::unique_ptr<String16>& callingPackageName, int32_t uid,
- const String16& packageName, int32_t opCode, const std::unique_ptr<String16>& featureId,
- const String16& message) {
- sp<IAppOpsService> service = getService();
- if (service != nullptr) {
- return service->noteAsyncOp(callingPackageName, uid, packageName, opCode, featureId,
- message);
- }
+ return appOpsToNote[opcode] == 2;
}
} // namespace android
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 7384466..a5555a3 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -47,13 +47,16 @@
}
virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName,
- const std::unique_ptr<String16>& featureId) {
+ const std::unique_ptr<String16>& featureId, bool shouldCollectAsyncNotedOp,
+ const String16& message) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
data.writeInt32(code);
data.writeInt32(uid);
data.writeString16(packageName);
data.writeString16(featureId);
+ data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0);
+ data.writeString16(message);
remote()->transact(NOTE_OPERATION_TRANSACTION, data, &reply);
// fail on exception
if (reply.readExceptionCode() != 0) return MODE_ERRORED;
@@ -62,7 +65,7 @@
virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
const String16& packageName, const std::unique_ptr<String16>& featureId,
- bool startIfModeDefault) {
+ bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
data.writeStrongBinder(token);
@@ -71,6 +74,8 @@
data.writeString16(packageName);
data.writeString16(featureId);
data.writeInt32(startIfModeDefault ? 1 : 0);
+ data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0);
+ data.writeString16(message);
remote()->transact(START_OPERATION_TRANSACTION, data, &reply);
// fail on exception
if (reply.readExceptionCode() != 0) return MODE_ERRORED;
@@ -139,20 +144,6 @@
remote()->transact(SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION, data, &reply);
}
- virtual void noteAsyncOp(const std::unique_ptr<String16>& callingPackageName, int32_t uid,
- const String16& packageName, int32_t opCode, const std::unique_ptr<String16>& featureId,
- const String16& message) {
- Parcel data, reply;
- data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
- data.writeString16(callingPackageName);
- data.writeInt32(uid);
- data.writeString16(packageName);
- data.writeInt32(opCode);
- data.writeString16(featureId);
- data.writeString16(message);
- remote()->transact(NOTE_ASYNC_OP_TRANSACTION, data, &reply);
- }
-
virtual bool shouldCollectNotes(int32_t opCode) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -193,7 +184,10 @@
String16 packageName = data.readString16();
std::unique_ptr<String16> featureId;
data.readString16(&featureId);
- int32_t res = noteOperation(code, uid, packageName, featureId);
+ bool shouldCollectAsyncNotedOp = data.readInt32() == 1;
+ String16 message = data.readString16();
+ int32_t res = noteOperation(code, uid, packageName, featureId,
+ shouldCollectAsyncNotedOp, message);
reply->writeNoException();
reply->writeInt32(res);
return NO_ERROR;
@@ -207,8 +201,10 @@
std::unique_ptr<String16> featureId;
data.readString16(&featureId);
bool startIfModeDefault = data.readInt32() == 1;
+ bool shouldCollectAsyncNotedOp = data.readInt32() == 1;
+ String16 message = data.readString16();
int32_t res = startOperation(token, code, uid, packageName, featureId,
- startIfModeDefault);
+ startIfModeDefault, shouldCollectAsyncNotedOp, message);
reply->writeNoException();
reply->writeInt32(res);
return NO_ERROR;
@@ -267,20 +263,6 @@
reply->writeNoException();
return NO_ERROR;
} break;
- case NOTE_ASYNC_OP_TRANSACTION: {
- CHECK_INTERFACE(IAppOpsService, data, reply);
- std::unique_ptr<String16> callingPackageName;
- data.readString16(&callingPackageName);
- int32_t uid = data.readInt32();
- String16 packageName = data.readString16();
- int32_t opCode = data.readInt32();
- std::unique_ptr<String16> featureId;
- data.readString16(&featureId);
- String16 message = data.readString16();
- noteAsyncOp(callingPackageName, uid, packageName, opCode, featureId, message);
- reply->writeNoException();
- return NO_ERROR;
- } break;
case SHOULD_COLLECT_NOTES_TRANSACTION: {
CHECK_INTERFACE(IAppOpsService, data, reply);
int32_t opCode = data.readInt32();
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 22a0179..5b6eb68 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -151,17 +151,12 @@
void stopWatchingMode(const sp<IAppOpsCallback>& callback);
int32_t permissionToOpCode(const String16& permission);
void setCameraAudioRestriction(int32_t mode);
- void noteAsyncOp(const std::unique_ptr<String16>& callingPackageName, int32_t uid,
- const String16& packageName, int32_t opCode, const std::unique_ptr<String16>& featureId,
- const String16& message);
private:
Mutex mLock;
sp<IAppOpsService> mService;
sp<IAppOpsService> getService();
- void markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
- const std::unique_ptr<String16>& featureId, const String16& message);
bool shouldCollectNotes(int32_t opCode);
};
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index 68a917e..1b4bcce 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -36,10 +36,11 @@
virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName,
- const std::unique_ptr<String16>& featureId) = 0;
+ const std::unique_ptr<String16>& featureId, bool shouldCollectAsyncNotedOp,
+ const String16& message) = 0;
virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
const String16& packageName, const std::unique_ptr<String16>& featureId,
- bool startIfModeDefault) = 0;
+ bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) = 0;
virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
const String16& packageName, const std::unique_ptr<String16>& featureId) = 0;
virtual void startWatchingMode(int32_t op, const String16& packageName,
@@ -49,9 +50,6 @@
virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid,
const String16& packageName) = 0;
virtual void setCameraAudioRestriction(int32_t mode) = 0;
- virtual void noteAsyncOp(const std::unique_ptr<String16>& callingPackageName, int32_t uid,
- const String16& packageName, int32_t opCode, const std::unique_ptr<String16>& featureId,
- const String16& message) = 0;
virtual bool shouldCollectNotes(int32_t opCode) = 0;
enum {
@@ -63,9 +61,8 @@
STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5,
PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7,
- NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8,
- SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9,
- SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10,
+ SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8,
+ SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9,
};
enum {
diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp
index 85137f5..f2d0943 100644
--- a/libs/graphicsenv/GpuStatsInfo.cpp
+++ b/libs/graphicsenv/GpuStatsInfo.cpp
@@ -87,6 +87,7 @@
if ((status = parcel->writeInt64Vector(angleDriverLoadingTime)) != OK) return status;
if ((status = parcel->writeBool(cpuVulkanInUse)) != OK) return status;
if ((status = parcel->writeBool(falsePrerotation)) != OK) return status;
+ if ((status = parcel->writeBool(gles1InUse)) != OK) return status;
return OK;
}
@@ -99,6 +100,7 @@
if ((status = parcel->readInt64Vector(&angleDriverLoadingTime)) != OK) return status;
if ((status = parcel->readBool(&cpuVulkanInUse)) != OK) return status;
if ((status = parcel->readBool(&falsePrerotation)) != OK) return status;
+ if ((status = parcel->readBool(&gles1InUse)) != OK) return status;
return OK;
}
@@ -108,6 +110,7 @@
StringAppendF(&result, "driverVersionCode = %" PRIu64 "\n", driverVersionCode);
StringAppendF(&result, "cpuVulkanInUse = %d\n", cpuVulkanInUse);
StringAppendF(&result, "falsePrerotation = %d\n", falsePrerotation);
+ StringAppendF(&result, "gles1InUse = %d\n", gles1InUse);
result.append("glDriverLoadingTime:");
for (int32_t loadingTime : glDriverLoadingTime) {
StringAppendF(&result, " %d", loadingTime);
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
index 7959652..9aba69f 100644
--- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -71,6 +71,7 @@
std::vector<int64_t> angleDriverLoadingTime = {};
bool cpuVulkanInUse = false;
bool falsePrerotation = false;
+ bool gles1InUse = false;
};
/*
@@ -95,6 +96,7 @@
enum Stats {
CPU_VULKAN_IN_USE = 0,
FALSE_PREROTATION = 1,
+ GLES_1_IN_USE = 2,
};
GpuStatsInfo() = default;
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 1fc7927..5162ba4 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -984,6 +984,8 @@
if (attr == EGL_CONTEXT_CLIENT_VERSION) {
if (value == 1) {
version = egl_connection_t::GLESv1_INDEX;
+ android::GraphicsEnv::getInstance().setTargetStats(
+ android::GpuStatsInfo::Stats::GLES_1_IN_USE);
} else if (value == 2 || value == 3) {
version = egl_connection_t::GLESv2_INDEX;
}
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index 67babd4..7fff6ed 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -145,6 +145,9 @@
case GpuStatsInfo::Stats::FALSE_PREROTATION:
mAppStats[appStatsKey].falsePrerotation = true;
break;
+ case GpuStatsInfo::Stats::GLES_1_IN_USE:
+ mAppStats[appStatsKey].gles1InUse = true;
+ break;
default:
break;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index c4f91be..12b0ddd 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -42,8 +42,6 @@
using android::Rect;
using android::Region;
using android::sp;
-using android::hardware::Return;
-using android::hardware::Void;
namespace HWC2 {
@@ -60,188 +58,8 @@
return keys.find(key) != keys.end();
}
-class ComposerCallbackBridge : public Hwc2::IComposerCallback {
-public:
- ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId,
- bool vsyncSwitchingSupported)
- : mCallback(callback),
- mSequenceId(sequenceId),
- mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
-
- Return<void> onHotplug(Hwc2::Display display,
- IComposerCallback::Connection conn) override
- {
- HWC2::Connection connection = static_cast<HWC2::Connection>(conn);
- mCallback->onHotplugReceived(mSequenceId, display, connection);
- return Void();
- }
-
- Return<void> onRefresh(Hwc2::Display display) override
- {
- mCallback->onRefreshReceived(mSequenceId, display);
- return Void();
- }
-
- Return<void> onVsync(Hwc2::Display 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 Void();
- }
-
- Return<void> onVsync_2_4(Hwc2::Display display, int64_t timestamp,
- Hwc2::VsyncPeriodNanos vsyncPeriodNanos) override {
- if (mVsyncSwitchingSupported) {
- // TODO(b/140201379): use vsyncPeriodNanos in the new DispSync
- mCallback->onVsyncReceived(mSequenceId, display, timestamp,
- std::make_optional(vsyncPeriodNanos));
- } else {
- ALOGW("Unexpected onVsync_2_4 callback on composer <= 2.3, ignoring.");
- }
- return Void();
- }
-
- Return<void> onVsyncPeriodTimingChanged(
- Hwc2::Display display,
- const Hwc2::VsyncPeriodChangeTimeline& updatedTimeline) override {
- hwc_vsync_period_change_timeline_t timeline;
- timeline.newVsyncAppliedTimeNanos = updatedTimeline.newVsyncAppliedTimeNanos;
- timeline.refreshRequired = updatedTimeline.refreshRequired;
- timeline.refreshTimeNanos = updatedTimeline.refreshTimeNanos;
- mCallback->onVsyncPeriodTimingChangedReceived(mSequenceId, display, timeline);
- return Void();
- }
-
-private:
- ComposerCallback* mCallback;
- int32_t mSequenceId;
- const bool mVsyncSwitchingSupported;
-};
-
} // namespace anonymous
-
-// Device methods
-
-Device::Device(std::unique_ptr<android::Hwc2::Composer> composer) : mComposer(std::move(composer)) {
- loadCapabilities();
-}
-
-void Device::registerCallback(ComposerCallback* callback, int32_t sequenceId) {
- if (mRegisteredCallback) {
- ALOGW("Callback already registered. Ignored extra registration "
- "attempt.");
- return;
- }
- mRegisteredCallback = true;
- sp<ComposerCallbackBridge> callbackBridge(
- new ComposerCallbackBridge(callback, sequenceId,
- mComposer->isVsyncPeriodSwitchSupported()));
- mComposer->registerCallback(callbackBridge);
-}
-
-// Required by HWC2 device
-
-std::string Device::dump() const
-{
- return mComposer->dumpDebugInfo();
-}
-
-uint32_t Device::getMaxVirtualDisplayCount() const
-{
- return mComposer->getMaxVirtualDisplayCount();
-}
-
-Error Device::getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
- std::vector<uint8_t>* outData) const {
- auto intError = mComposer->getDisplayIdentificationData(hwcDisplayId, outPort, outData);
- return static_cast<Error>(intError);
-}
-
-Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
- PixelFormat* format, Display** outDisplay)
-{
- ALOGI("Creating virtual display");
-
- hwc2_display_t displayId = 0;
- auto intError = mComposer->createVirtualDisplay(width, height,
- format, &displayId);
- auto error = static_cast<Error>(intError);
- if (error != Error::None) {
- return error;
- }
-
- auto display = std::make_unique<impl::Display>(*mComposer.get(), mCapabilities, displayId,
- DisplayType::Virtual);
- display->setConnected(true);
- *outDisplay = display.get();
- mDisplays.emplace(displayId, std::move(display));
- ALOGI("Created virtual display");
- return Error::None;
-}
-
-void Device::destroyDisplay(hwc2_display_t displayId)
-{
- ALOGI("Destroying display %" PRIu64, displayId);
- mDisplays.erase(displayId);
-}
-
-void Device::onHotplug(hwc2_display_t displayId, Connection connection) {
- if (connection == Connection::Connected) {
- // If we get a hotplug connected event for a display we already have,
- // destroy the display and recreate it. This will force us to requery
- // the display params and recreate all layers on that display.
- auto oldDisplay = getDisplayById(displayId);
- if (oldDisplay != nullptr && oldDisplay->isConnected()) {
- ALOGI("Hotplug connecting an already connected display."
- " Clearing old display state.");
- }
- mDisplays.erase(displayId);
-
- auto newDisplay = std::make_unique<impl::Display>(*mComposer.get(), mCapabilities,
- displayId, DisplayType::Physical);
- newDisplay->setConnected(true);
- mDisplays.emplace(displayId, std::move(newDisplay));
- } else if (connection == Connection::Disconnected) {
- // The display will later be destroyed by a call to
- // destroyDisplay(). For now we just mark it disconnected.
- auto display = getDisplayById(displayId);
- if (display) {
- display->setConnected(false);
- } else {
- ALOGW("Attempted to disconnect unknown display %" PRIu64,
- displayId);
- }
- }
-}
-
-// Other Device methods
-
-Display* Device::getDisplayById(hwc2_display_t id) {
- auto iter = mDisplays.find(id);
- return iter == mDisplays.end() ? nullptr : iter->second.get();
-}
-
-// Device initialization methods
-
-void Device::loadCapabilities()
-{
- static_assert(sizeof(Capability) == sizeof(int32_t),
- "Capability size has changed");
- auto capabilities = mComposer->getCapabilities();
- for (auto capability : capabilities) {
- mCapabilities.emplace(static_cast<Capability>(capability));
- }
-}
-
-Error Device::flushCommands()
-{
- return static_cast<Error>(mComposer->executeCommands());
-}
-
// Display methods
Display::~Display() = default;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 59f36d0..8b532e3 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -52,7 +52,6 @@
namespace HWC2 {
-class Display;
class Layer;
using VsyncPeriodChangeConstraints = hwc_vsync_period_change_constraints_t;
using VsyncPeriodChangeTimeline = hwc_vsync_period_change_timeline_t;
@@ -81,56 +80,6 @@
virtual ~ComposerCallback() = default;
};
-// C++ Wrapper around hwc2_device_t. Load all functions pointers
-// and handle callback registration.
-class Device
-{
-public:
- explicit Device(std::unique_ptr<android::Hwc2::Composer> composer);
-
- void registerCallback(ComposerCallback* callback, int32_t sequenceId);
-
- // Required by HWC2
-
- std::string dump() const;
-
- const std::unordered_set<Capability>& getCapabilities() const {
- return mCapabilities;
- };
-
- uint32_t getMaxVirtualDisplayCount() const;
- Error getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
- std::vector<uint8_t>* outData) const;
-
- Error createVirtualDisplay(uint32_t width, uint32_t height,
- android::ui::PixelFormat* format, Display** outDisplay);
- void destroyDisplay(hwc2_display_t displayId);
-
- void onHotplug(hwc2_display_t displayId, Connection connection);
-
- // Other Device methods
-
- Display* getDisplayById(hwc2_display_t id);
-
- android::Hwc2::Composer* getComposer() { return mComposer.get(); }
-
- // We buffer most state changes and flush them implicitly with
- // Display::validate, Display::present, and Display::presentOrValidate.
- // This method provides an explicit way to flush state changes to HWC.
- Error flushCommands();
-
-private:
- // Initialization methods
-
- void loadCapabilities();
-
- // Member variables
- std::unique_ptr<android::Hwc2::Composer> mComposer;
- std::unordered_set<Capability> mCapabilities;
- std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
- bool mRegisteredCallback = false;
-};
-
// Convenience C++ class to access hwc2_device_t Display functions directly.
class Display {
public:
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 9accefb..0a7009b 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -65,14 +65,88 @@
#define RETURN_IF_HWC_ERROR(error, displayId, ...) \
RETURN_IF_HWC_ERROR_FOR(__FUNCTION__, error, displayId, __VA_ARGS__)
+namespace {
+
+using android::hardware::Return;
+using android::hardware::Void;
+
+class ComposerCallbackBridge : public android::Hwc2::IComposerCallback {
+public:
+ ComposerCallbackBridge(HWC2::ComposerCallback* callback, int32_t sequenceId,
+ bool vsyncSwitchingSupported)
+ : mCallback(callback),
+ mSequenceId(sequenceId),
+ mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
+
+ android::hardware::Return<void> onHotplug(
+ android::Hwc2::Display display,
+ android::Hwc2::IComposerCallback::Connection conn) override {
+ HWC2::Connection connection = static_cast<HWC2::Connection>(conn);
+ mCallback->onHotplugReceived(mSequenceId, display, connection);
+ return android::hardware::Void();
+ }
+
+ android::hardware::Return<void> onRefresh(android::Hwc2::Display display) override {
+ mCallback->onRefreshReceived(mSequenceId, display);
+ return android::hardware::Void();
+ }
+
+ android::hardware::Return<void> onVsync(android::Hwc2::Display 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();
+ }
+
+ android::hardware::Return<void> onVsync_2_4(
+ android::Hwc2::Display display, int64_t timestamp,
+ android::Hwc2::VsyncPeriodNanos vsyncPeriodNanos) override {
+ if (mVsyncSwitchingSupported) {
+ // TODO(b/140201379): use vsyncPeriodNanos in the new DispSync
+ 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();
+ }
+
+ android::hardware::Return<void> onVsyncPeriodTimingChanged(
+ android::Hwc2::Display display,
+ const android::Hwc2::VsyncPeriodChangeTimeline& updatedTimeline) override {
+ hwc_vsync_period_change_timeline_t timeline;
+ timeline.newVsyncAppliedTimeNanos = updatedTimeline.newVsyncAppliedTimeNanos;
+ timeline.refreshRequired = updatedTimeline.refreshRequired;
+ timeline.refreshTimeNanos = updatedTimeline.refreshTimeNanos;
+ mCallback->onVsyncPeriodTimingChangedReceived(mSequenceId, display, timeline);
+ return android::hardware::Void();
+ }
+
+private:
+ HWC2::ComposerCallback* mCallback;
+ const int32_t mSequenceId;
+ const bool mVsyncSwitchingSupported;
+};
+
+} // namespace
+
namespace android {
HWComposer::~HWComposer() = default;
namespace impl {
-HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer)
- : mHwcDevice(std::make_unique<HWC2::Device>(std::move(composer))) {}
+HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer) : mComposer(std::move(composer)) {
+ loadCapabilities();
+}
+
+HWComposer::HWComposer(const std::string& composerServiceName)
+ : mComposer(std::make_unique<Hwc2::impl::Composer>(composerServiceName)) {
+ loadCapabilities();
+}
HWComposer::~HWComposer() {
mDisplayData.clear();
@@ -80,12 +154,21 @@
void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
int32_t sequenceId) {
- mHwcDevice->registerCallback(callback, sequenceId);
+ if (mRegisteredCallback) {
+ ALOGW("Callback already registered. Ignored extra registration attempt.");
+ return;
+ }
+ mRegisteredCallback = true;
+ sp<ComposerCallbackBridge> callbackBridge(
+ new ComposerCallbackBridge(callback, sequenceId,
+ mComposer->isVsyncPeriodSwitchSupported()));
+ mComposer->registerCallback(callbackBridge);
}
bool HWComposer::getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
DisplayIdentificationData* outData) const {
- const auto error = mHwcDevice->getDisplayIdentificationData(hwcDisplayId, outPort, outData);
+ const auto error = static_cast<HWC2::Error>(
+ mComposer->getDisplayIdentificationData(hwcDisplayId, outPort, outData));
if (error != HWC2::Error::None) {
if (error != HWC2::Error::Unsupported) {
LOG_HWC_DISPLAY_ERROR(hwcDisplayId, to_string(error).c_str());
@@ -95,9 +178,8 @@
return true;
}
-bool HWComposer::hasCapability(HWC2::Capability capability) const
-{
- return mHwcDevice->getCapabilities().count(capability) > 0;
+bool HWComposer::hasCapability(HWC2::Capability capability) const {
+ return mCapabilities.count(capability) > 0;
}
bool HWComposer::hasDisplayCapability(const std::optional<DisplayId>& displayId,
@@ -133,13 +215,33 @@
hwcDisplayId == mInternalHwcDisplayId ? "internal" : "external",
to_string(info->id).c_str(), hwcDisplayId);
- mHwcDevice->onHotplug(hwcDisplayId, connection);
-
- // Disconnect is handled through HWComposer::disconnectDisplay via
- // SurfaceFlinger's onHotplugReceived callback handling
if (connection == HWC2::Connection::Connected) {
- mDisplayData[info->id].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
+ auto& displayData = mDisplayData[info->id];
+ // If we get a hotplug connected event for a display we already have,
+ // destroy the display and recreate it. This will force us to requery
+ // the display params and recreate all layers on that display.
+ if (displayData.hwcDisplay != nullptr && displayData.hwcDisplay->isConnected()) {
+ ALOGI("Hotplug connecting an already connected display."
+ " Clearing old display state.");
+ }
+ displayData.hwcDisplay.reset();
+ auto newDisplay =
+ std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities, hwcDisplayId,
+ HWC2::DisplayType::Physical);
+ newDisplay->setConnected(true);
+ displayData.hwcDisplay = std::move(newDisplay);
mPhysicalDisplayIdMap[hwcDisplayId] = info->id;
+ } else if (connection == HWC2::Connection::Disconnected) {
+ // The display will later be destroyed by a call to
+ // destroyDisplay(). For now we just mark it disconnected.
+ auto& displayData = mDisplayData[info->id];
+ if (displayData.hwcDisplay) {
+ displayData.hwcDisplay->setConnected(false);
+ } else {
+ ALOGW("Attempted to disconnect unknown display %" PRIu64, hwcDisplayId);
+ }
+ // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay
+ // via SurfaceFlinger's onHotplugReceived callback handling
}
return info;
@@ -197,14 +299,18 @@
height, SurfaceFlinger::maxVirtualDisplaySize);
return {};
}
- HWC2::Display* display;
- auto error = mHwcDevice->createVirtualDisplay(width, height, format,
- &display);
+ hwc2_display_t hwcDisplayId = 0;
+ const auto error = static_cast<HWC2::Error>(
+ mComposer->createVirtualDisplay(width, height, format, &hwcDisplayId));
if (error != HWC2::Error::None) {
ALOGE("%s: Failed to create HWC virtual display", __FUNCTION__);
return {};
}
+ auto display = std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities,
+ hwcDisplayId, HWC2::DisplayType::Virtual);
+ display->setConnected(true);
+
DisplayId displayId;
if (mFreeVirtualDisplayIds.empty()) {
displayId = getVirtualDisplayId(mNextVirtualDisplayId++);
@@ -214,7 +320,7 @@
}
auto& displayData = mDisplayData[displayId];
- displayData.hwcDisplay = display;
+ displayData.hwcDisplay = std::move(display);
displayData.isVirtual = true;
--mRemainingHwcVirtualDisplays;
@@ -224,9 +330,8 @@
HWC2::Layer* HWComposer::createLayer(DisplayId displayId) {
RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
- auto display = mDisplayData[displayId].hwcDisplay;
HWC2::Layer* layer;
- auto error = display->createLayer(&layer);
+ auto error = mDisplayData[displayId].hwcDisplay->createLayer(&layer);
RETURN_IF_HWC_ERROR(error, displayId, nullptr);
return layer;
}
@@ -234,8 +339,7 @@
void HWComposer::destroyLayer(DisplayId displayId, HWC2::Layer* layer) {
RETURN_IF_INVALID_DISPLAY(displayId);
- auto display = mDisplayData[displayId].hwcDisplay;
- auto error = display->destroyLayer(layer);
+ auto error = mDisplayData[displayId].hwcDisplay->destroyLayer(layer);
RETURN_IF_HWC_ERROR(error, displayId);
}
@@ -484,8 +588,8 @@
if (displayData.validateWasSkipped) {
// explicitly flush all pending commands
- auto error = mHwcDevice->flushCommands();
- RETURN_IF_HWC_ERROR_FOR("flushCommands", error, displayId, UNKNOWN_ERROR);
+ auto error = static_cast<HWC2::Error>(mComposer->executeCommands());
+ RETURN_IF_HWC_ERROR_FOR("executeCommands", error, displayId, UNKNOWN_ERROR);
RETURN_IF_HWC_ERROR_FOR("present", displayData.presentError, displayId, UNKNOWN_ERROR);
return NO_ERROR;
}
@@ -600,8 +704,6 @@
}
const auto hwcDisplayId = displayData.hwcDisplay->getId();
- mPhysicalDisplayIdMap.erase(hwcDisplayId);
- mDisplayData.erase(displayId);
// TODO(b/74619554): Select internal/external display from remaining displays.
if (hwcDisplayId == mInternalHwcDisplayId) {
@@ -609,8 +711,8 @@
} else if (hwcDisplayId == mExternalHwcDisplayId) {
mExternalHwcDisplayId.reset();
}
-
- mHwcDevice->destroyDisplay(hwcDisplayId);
+ mPhysicalDisplayIdMap.erase(hwcDisplayId);
+ mDisplayData.erase(displayId);
}
status_t HWComposer::setOutputBuffer(DisplayId displayId, const sp<Fence>& acquireFence,
@@ -761,10 +863,7 @@
}
void HWComposer::dump(std::string& result) const {
- // TODO: In order to provide a dump equivalent to HWC1, we need to shadow
- // all the state going into the layers. This is probably better done in
- // Layer itself, but it's going to take a bit of work to get there.
- result.append(mHwcDevice->dump());
+ result.append(mComposer->dumpDebugInfo());
}
std::optional<DisplayId> HWComposer::toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const {
@@ -830,5 +929,17 @@
: "External display"};
}
+void HWComposer::loadCapabilities() {
+ static_assert(sizeof(HWC2::Capability) == sizeof(int32_t), "Capability size has changed");
+ auto capabilities = mComposer->getCapabilities();
+ for (auto capability : capabilities) {
+ mCapabilities.emplace(static_cast<HWC2::Capability>(capability));
+ }
+}
+
+uint32_t HWComposer::getMaxVirtualDisplayCount() const {
+ return mComposer->getMaxVirtualDisplayCount();
+}
+
} // namespace impl
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index c51002c..a0dabb4 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -207,6 +207,7 @@
class HWComposer final : public android::HWComposer {
public:
explicit HWComposer(std::unique_ptr<Hwc2::Composer> composer);
+ explicit HWComposer(const std::string& composerServiceName);
~HWComposer() override;
@@ -325,7 +326,7 @@
// for debugging ----------------------------------------------------------
void dump(std::string& out) const override;
- Hwc2::Composer* getComposer() const override { return mHwcDevice->getComposer(); }
+ Hwc2::Composer* getComposer() const override { return mComposer.get(); }
// TODO(b/74619554): Remove special cases for internal/external display.
std::optional<hwc2_display_t> getInternalHwcDisplayId() const override {
@@ -343,11 +344,12 @@
friend TestableSurfaceFlinger;
std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
+ void loadCapabilities();
+ uint32_t getMaxVirtualDisplayCount() const;
struct DisplayData {
bool isVirtual = false;
-
- HWC2::Display* hwcDisplay = nullptr;
+ std::unique_ptr<HWC2::Display> hwcDisplay;
sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
buffer_handle_t outbufHandle = nullptr;
@@ -369,9 +371,9 @@
std::unordered_map<DisplayId, DisplayData> mDisplayData;
- // This must be destroyed before mDisplayData, because destructor may call back into HWComposer
- // and look up DisplayData.
- std::unique_ptr<HWC2::Device> mHwcDevice;
+ std::unique_ptr<android::Hwc2::Composer> mComposer;
+ std::unordered_set<HWC2::Capability> mCapabilities;
+ bool mRegisteredCallback = false;
std::unordered_map<hwc2_display_t, DisplayId> mPhysicalDisplayIdMap;
std::optional<hwc2_display_t> mInternalHwcDisplayId;
@@ -380,7 +382,7 @@
std::unordered_set<DisplayId> mFreeVirtualDisplayIds;
uint32_t mNextVirtualDisplayId = 0;
- uint32_t mRemainingHwcVirtualDisplays{mHwcDevice->getMaxVirtualDisplayCount()};
+ uint32_t mRemainingHwcVirtualDisplays{getMaxVirtualDisplayCount()};
};
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 571c9ca..bd4b0ec 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -27,16 +27,14 @@
namespace android {
-DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset,
- nsecs_t offsetThresholdForNextVsync, bool traceVsync,
+DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
const char* name)
: mName(name),
mValue(base::StringPrintf("VSYNC-%s", name), 0),
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
mDispSync(dispSync),
- mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset),
- mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {}
+ mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset) {}
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
@@ -67,10 +65,6 @@
void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) {
std::lock_guard lock(mVsyncMutex);
const nsecs_t period = mDispSync->getPeriod();
- // Check if offset should be handled as negative
- if (phaseOffset >= mOffsetThresholdForNextVsync) {
- phaseOffset -= period;
- }
// Normalize phaseOffset to [-period, period)
const int numPeriods = phaseOffset / period;
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 536464e..328b8c1 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -26,8 +26,7 @@
class DispSyncSource final : public VSyncSource, private DispSync::Callback {
public:
- DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, nsecs_t offsetThresholdForNextVsync,
- bool traceVsync, const char* name);
+ DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name);
~DispSyncSource() override = default;
@@ -55,7 +54,6 @@
std::mutex mVsyncMutex;
TracedOrdinal<nsecs_t> mPhaseOffset GUARDED_BY(mVsyncMutex);
- const nsecs_t mOffsetThresholdForNextVsync;
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
};
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
index 6c502e6..fa46e6f 100644
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -45,7 +45,6 @@
const char* getName() const override { return "inject"; }
void setVSyncEnabled(bool) override {}
void setPhaseOffset(nsecs_t) override {}
- void pauseVsyncCallback(bool) {}
private:
std::mutex mCallbackMutex;
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 12832a6..4330742 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -35,45 +35,48 @@
namespace android::scheduler {
-PhaseOffsets::~PhaseOffsets() = default;
+PhaseConfiguration::~PhaseConfiguration() = default;
namespace impl {
-PhaseOffsets::PhaseOffsets() {
- // Below defines the threshold when an offset is considered to be negative, i.e. targeting
- // for the N+2 vsync instead of N+1. This means that:
- // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
- // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
- const nsecs_t thresholdForNextVsync =
- getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
- .value_or(std::numeric_limits<nsecs_t>::max());
-
- mDefaultOffsets = getDefaultOffsets(thresholdForNextVsync);
- mHighFpsOffsets = getHighFpsOffsets(thresholdForNextVsync);
-}
-
-PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const {
- // TODO(145561086): Once offsets are common for all refresh rates we can remove the magic
- // number for refresh rate
- if (fps > 65.0f) {
- return mHighFpsOffsets;
- } else {
- return mDefaultOffsets;
- }
-}
+PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
+ : // Below defines the threshold when an offset is considered to be negative, i.e. targeting
+ // for the N+2 vsync instead of N+1. This means that:
+ // For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
+ // For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
+ mThresholdForNextVsync(getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
+ .value_or(std::numeric_limits<nsecs_t>::max())),
+ mOffsets(initializeOffsets(refreshRateConfigs)),
+ mRefreshRateFps(refreshRateConfigs.getCurrentRefreshRate().fps) {}
void PhaseOffsets::dump(std::string& result) const {
- const auto [early, earlyGl, late, threshold] = getCurrentOffsets();
+ const auto [early, earlyGl, late] = getCurrentOffsets();
using base::StringAppendF;
StringAppendF(&result,
" app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
" early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
" GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
"next VSYNC threshold: %9" PRId64 " ns\n",
- late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, threshold);
+ late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf,
+ mThresholdForNextVsync);
}
-PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVsync) {
+std::unordered_map<float, PhaseDurations::Offsets> PhaseOffsets::initializeOffsets(
+ const scheduler::RefreshRateConfigs& refreshRateConfigs) const {
+ std::unordered_map<float, PhaseDurations::Offsets> offsets;
+
+ for (const auto& [ignored, refreshRate] : refreshRateConfigs.getAllRefreshRates()) {
+ const nsecs_t vsyncDuration = static_cast<nsecs_t>(1e9f / refreshRate.fps);
+ if (refreshRate.fps > 65.0f) {
+ offsets.emplace(refreshRate.fps, getHighFpsOffsets(vsyncDuration));
+ } else {
+ offsets.emplace(refreshRate.fps, getDefaultOffsets(vsyncDuration));
+ }
+ }
+ return offsets;
+}
+
+PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
@@ -82,19 +85,32 @@
const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns");
const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns");
- return {{earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs),
- earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs)},
+ return {
+ {
+ earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
+ ? earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
+ : earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
- {earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs),
- earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs)},
+ earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs),
+ },
+ {
+ earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) < mThresholdForNextVsync
+ ? earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs)
+ : earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs) - vsyncDuration,
- {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs},
+ earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs),
+ },
+ {
+ sfVsyncPhaseOffsetNs < mThresholdForNextVsync
+ ? sfVsyncPhaseOffsetNs
+ : sfVsyncPhaseOffsetNs - vsyncDuration,
- thresholdForNextVsync};
+ vsyncPhaseOffsetNs,
+ },
+ };
}
-PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t thresholdForNextVsync) {
- // TODO(b/122905996): Define these in device.mk.
+PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
const int highFpsLateAppOffsetNs =
getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
const int highFpsLateSfOffsetNs =
@@ -106,15 +122,195 @@
const auto highFpsEarlyGlAppOffsetNs =
getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
- return {{highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs),
- highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs)},
+ return {
+ {
+ highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) < mThresholdForNextVsync
+ ? highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs)
+ : highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) -
+ vsyncDuration,
- {highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs),
- highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs)},
+ highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs),
+ },
+ {
+ highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) <
+ mThresholdForNextVsync
+ ? highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs)
+ : highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) -
+ vsyncDuration,
- {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs},
+ highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs),
+ },
+ {
+ highFpsLateSfOffsetNs < mThresholdForNextVsync
+ ? highFpsLateSfOffsetNs
+ : highFpsLateSfOffsetNs - vsyncDuration,
- thresholdForNextVsync};
+ highFpsLateAppOffsetNs,
+ },
+ };
+}
+
+static void validateSysprops() {
+ const auto validatePropertyBool = [](const char* prop) {
+ LOG_ALWAYS_FATAL_IF(!property_get_bool(prop, false), "%s is false", prop);
+ };
+
+ validatePropertyBool("debug.sf.use_phase_offsets_as_durations");
+
+ LOG_ALWAYS_FATAL_IF(sysprop::vsync_event_phase_offset_ns(-1) != -1,
+ "ro.surface_flinger.vsync_event_phase_offset_ns is set but expecting "
+ "duration");
+
+ LOG_ALWAYS_FATAL_IF(sysprop::vsync_sf_event_phase_offset_ns(-1) != -1,
+ "ro.surface_flinger.vsync_sf_event_phase_offset_ns is set but expecting "
+ "duration");
+
+ const auto validateProperty = [](const char* prop) {
+ LOG_ALWAYS_FATAL_IF(getProperty(prop).has_value(),
+ "%s is set to %" PRId64 " but expecting duration", prop,
+ getProperty(prop).value_or(-1));
+ };
+
+ validateProperty("debug.sf.early_phase_offset_ns");
+ validateProperty("debug.sf.early_gl_phase_offset_ns");
+ validateProperty("debug.sf.early_app_phase_offset_ns");
+ validateProperty("debug.sf.early_gl_app_phase_offset_ns");
+ validateProperty("debug.sf.high_fps_late_app_phase_offset_ns");
+ validateProperty("debug.sf.high_fps_late_sf_phase_offset_ns");
+ validateProperty("debug.sf.high_fps_early_phase_offset_ns");
+ validateProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
+ validateProperty("debug.sf.high_fps_early_app_phase_offset_ns");
+ validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
+}
+
+static nsecs_t sfDurationToOffset(nsecs_t sfDuration, nsecs_t vsyncDuration) {
+ return sfDuration == -1 ? 1'000'000 : vsyncDuration - sfDuration % vsyncDuration;
+}
+
+static nsecs_t appDurationToOffset(nsecs_t appDuration, nsecs_t sfDuration, nsecs_t vsyncDuration) {
+ return sfDuration == -1 ? 1'000'000
+ : vsyncDuration - (appDuration + sfDuration) % vsyncDuration;
+}
+
+static std::vector<float> getRefreshRatesFromConfigs(
+ const android::scheduler::RefreshRateConfigs& refreshRateConfigs) {
+ const auto& allRefreshRates = refreshRateConfigs.getAllRefreshRates();
+ std::vector<float> refreshRates;
+ refreshRates.reserve(allRefreshRates.size());
+
+ for (const auto& [ignored, refreshRate] : allRefreshRates) {
+ refreshRates.emplace_back(refreshRate.fps);
+ }
+
+ return refreshRates;
+}
+
+std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets(
+ const std::vector<float>& refreshRates) const {
+ std::unordered_map<float, PhaseDurations::Offsets> offsets;
+
+ for (const auto fps : refreshRates) {
+ const nsecs_t vsyncDuration = static_cast<nsecs_t>(1e9f / fps);
+ offsets.emplace(fps,
+ Offsets{
+ {
+ mSfEarlyDuration < vsyncDuration
+ ? sfDurationToOffset(mSfEarlyDuration,
+ vsyncDuration)
+ : sfDurationToOffset(mSfEarlyDuration,
+ vsyncDuration) -
+ vsyncDuration,
+
+ appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration,
+ vsyncDuration),
+ },
+ {
+ mSfEarlyGlDuration < vsyncDuration
+ ? sfDurationToOffset(mSfEarlyGlDuration,
+ vsyncDuration)
+ : sfDurationToOffset(mSfEarlyGlDuration,
+ vsyncDuration) -
+ vsyncDuration,
+
+ appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration,
+ vsyncDuration),
+ },
+ {
+ mSfDuration < vsyncDuration
+ ? sfDurationToOffset(mSfDuration, vsyncDuration)
+ : sfDurationToOffset(mSfDuration, vsyncDuration) -
+ vsyncDuration,
+
+ appDurationToOffset(mAppDuration, mSfDuration,
+ vsyncDuration),
+ },
+ });
+ }
+ return offsets;
+}
+
+PhaseDurations::PhaseDurations(const scheduler::RefreshRateConfigs& refreshRateConfigs)
+ : PhaseDurations(getRefreshRatesFromConfigs(refreshRateConfigs),
+ refreshRateConfigs.getCurrentRefreshRate().fps,
+ getProperty("debug.sf.late.sf.duration").value_or(-1),
+ getProperty("debug.sf.late.app.duration").value_or(-1),
+ getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
+ getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
+ getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
+ getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
+ validateSysprops();
+}
+
+PhaseDurations::PhaseDurations(const std::vector<float>& refreshRates, float currentFps,
+ nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
+ nsecs_t appEarlyDuration, nsecs_t sfEarlyGlDuration,
+ nsecs_t appEarlyGlDuration)
+ : mSfDuration(sfDuration),
+ mAppDuration(appDuration),
+ mSfEarlyDuration(sfEarlyDuration),
+ mAppEarlyDuration(appEarlyDuration),
+ mSfEarlyGlDuration(sfEarlyGlDuration),
+ mAppEarlyGlDuration(appEarlyGlDuration),
+ mOffsets(initializeOffsets(refreshRates)),
+ mRefreshRateFps(currentFps) {}
+
+PhaseOffsets::Offsets PhaseDurations::getOffsetsForRefreshRate(float fps) const {
+ const auto iter = mOffsets.find(fps);
+ LOG_ALWAYS_FATAL_IF(iter == mOffsets.end());
+ return iter->second;
+}
+
+void PhaseDurations::dump(std::string& result) const {
+ const auto [early, earlyGl, late] = getCurrentOffsets();
+ using base::StringAppendF;
+ StringAppendF(&result,
+ " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
+ " ns\n"
+ " app duration: %9" PRId64 " ns\t SF duration: %9" PRId64
+ " ns\n"
+ " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
+ " ns\n"
+ " early app duration: %9" PRId64 " ns\t early SF duration: %9" PRId64
+ " ns\n"
+ " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
+ " ns\n"
+ " GL early app duration: %9" PRId64 " ns\tGL early SF duration: %9" PRId64
+ " ns\n",
+ late.app,
+
+ late.sf,
+
+ mAppDuration, mSfDuration,
+
+ early.app, early.sf,
+
+ mAppEarlyDuration, mSfEarlyDuration,
+
+ earlyGl.app,
+
+ earlyGl.sf,
+
+ mAppEarlyGlDuration, mSfEarlyGlDuration);
}
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index 7747f0c..c10efde 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -29,17 +29,11 @@
* different offsets will help us with latency. This class keeps track of
* which mode the device is on, and returns approprate offsets when needed.
*/
-class PhaseOffsets {
+class PhaseConfiguration {
public:
using Offsets = VSyncModulator::OffsetsConfig;
- virtual ~PhaseOffsets();
-
- nsecs_t getCurrentAppOffset() const { return getCurrentOffsets().late.app; }
- nsecs_t getCurrentSfOffset() const { return getCurrentOffsets().late.sf; }
- nsecs_t getOffsetThresholdForNextVsync() const {
- return getCurrentOffsets().thresholdForNextVsync;
- }
+ virtual ~PhaseConfiguration();
virtual Offsets getCurrentOffsets() const = 0;
virtual Offsets getOffsetsForRefreshRate(float fps) const = 0;
@@ -51,9 +45,51 @@
namespace impl {
-class PhaseOffsets : public scheduler::PhaseOffsets {
+/*
+ * This is the old implementation of phase offsets and considered as deprecated.
+ * PhaseDurations is the new implementation.
+ */
+class PhaseOffsets : public scheduler::PhaseConfiguration {
public:
- PhaseOffsets();
+ PhaseOffsets(const scheduler::RefreshRateConfigs&);
+
+ // Returns early, early GL, and late offsets for Apps and SF for a given refresh rate.
+ Offsets getOffsetsForRefreshRate(float fps) const override {
+ const auto iter = mOffsets.find(fps);
+ LOG_ALWAYS_FATAL_IF(iter == mOffsets.end());
+ return iter->second;
+ }
+
+ // Returns early, early GL, and late offsets for Apps and SF.
+ Offsets getCurrentOffsets() const override { return getOffsetsForRefreshRate(mRefreshRateFps); }
+
+ // This function should be called when the device is switching between different
+ // refresh rates, to properly update the offsets.
+ void setRefreshRateFps(float fps) override { mRefreshRateFps = fps; }
+
+ // Returns current offsets in human friendly format.
+ void dump(std::string& result) const override;
+
+private:
+ std::unordered_map<float, PhaseOffsets::Offsets> initializeOffsets(
+ const scheduler::RefreshRateConfigs&) const;
+ Offsets getDefaultOffsets(nsecs_t vsyncDuration) const;
+ Offsets getHighFpsOffsets(nsecs_t vsyncDuration) const;
+
+ const nsecs_t mThresholdForNextVsync;
+ const std::unordered_map<float, Offsets> mOffsets;
+
+ std::atomic<float> mRefreshRateFps;
+};
+
+/*
+ * Class that encapsulates the phase offsets for SurfaceFlinger and App.
+ * The offsets are calculated from durations for each one of the (late, early, earlyGL)
+ * offset types.
+ */
+class PhaseDurations : public scheduler::PhaseConfiguration {
+public:
+ PhaseDurations(const scheduler::RefreshRateConfigs&);
// Returns early, early GL, and late offsets for Apps and SF for a given refresh rate.
Offsets getOffsetsForRefreshRate(float fps) const override;
@@ -68,14 +104,28 @@
// Returns current offsets in human friendly format.
void dump(std::string& result) const override;
+protected:
+ // Used for unit tests
+ PhaseDurations(const std::vector<float>& refreshRates, float currentFps, nsecs_t sfDuration,
+ nsecs_t appDuration, nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
+ nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration);
+
private:
- static Offsets getDefaultOffsets(nsecs_t thresholdForNextVsync);
- static Offsets getHighFpsOffsets(nsecs_t thresholdForNextVsync);
+ std::unordered_map<float, PhaseDurations::Offsets> initializeOffsets(
+ const std::vector<float>&) const;
- std::atomic<float> mRefreshRateFps = 0;
+ const nsecs_t mSfDuration;
+ const nsecs_t mAppDuration;
- Offsets mDefaultOffsets;
- Offsets mHighFpsOffsets;
+ const nsecs_t mSfEarlyDuration;
+ const nsecs_t mAppEarlyDuration;
+
+ const nsecs_t mSfEarlyGlDuration;
+ const nsecs_t mAppEarlyGlDuration;
+
+ const std::unordered_map<float, Offsets> mOffsets;
+
+ std::atomic<float> mRefreshRateFps;
};
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 71a6a2f..71ebfc3 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -125,18 +125,16 @@
return *mPrimaryDispSync;
}
-std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
- const char* name, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync) {
+std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(const char* name,
+ nsecs_t phaseOffsetNs) {
return std::make_unique<DispSyncSource>(mPrimaryDispSync.get(), phaseOffsetNs,
- offsetThresholdForNextVsync, true /* traceVsync */,
- name);
+ true /* traceVsync */, name);
}
Scheduler::ConnectionHandle Scheduler::createConnection(
- const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
+ const char* connectionName, nsecs_t phaseOffsetNs,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
- auto vsyncSource =
- makePrimaryDispSyncSource(connectionName, phaseOffsetNs, offsetThresholdForNextVsync);
+ auto vsyncSource = makePrimaryDispSyncSource(connectionName, phaseOffsetNs);
auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource),
std::move(interceptCallback));
return createConnection(std::move(eventThread));
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 15277ce..2fa8b3f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -66,7 +66,6 @@
using ConnectionHandle = scheduler::ConnectionHandle;
ConnectionHandle createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
- nsecs_t offsetThresholdForNextVsync,
impl::EventThread::InterceptVSyncsCallback);
sp<IDisplayEventConnection> createDisplayEventConnection(ConnectionHandle,
@@ -149,8 +148,7 @@
Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>,
const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback);
- std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs,
- nsecs_t offsetThresholdForNextVsync);
+ std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs);
// Create a connection on the given EventThread.
ConnectionHandle createConnection(std::unique_ptr<EventThread>);
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index 63c0feb..704a5d5 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -43,6 +43,10 @@
struct Offsets {
nsecs_t sf;
nsecs_t app;
+
+ bool operator==(const Offsets& other) const { return sf == other.sf && app == other.app; }
+
+ bool operator!=(const Offsets& other) const { return !(*this == other); }
};
struct OffsetsConfig {
@@ -50,7 +54,11 @@
Offsets earlyGl; // As above but while compositing with GL.
Offsets late; // Default.
- nsecs_t thresholdForNextVsync;
+ bool operator==(const OffsetsConfig& other) const {
+ return early == other.early && earlyGl == other.earlyGl && late == other.late;
+ }
+
+ bool operator!=(const OffsetsConfig& other) const { return !(*this == other); }
};
VSyncModulator(Scheduler&, ConnectionHandle appConnectionHandle,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7f819dd..d02d783 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -260,7 +260,6 @@
mFrameTracer(std::make_unique<FrameTracer>()),
mEventQueue(mFactory.createMessageQueue()),
mCompositionEngine(mFactory.createCompositionEngine()),
- mPhaseOffsets(mFactory.createPhaseOffsets()),
mPendingSyncInputWindows(false) {}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
@@ -582,8 +581,6 @@
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- ALOGI("Phase offset: %" PRId64 " ns", mPhaseOffsets->getCurrentAppOffset());
-
Mutex::Autolock _l(mStateLock);
// Get a RenderEngine for the given display / config (can't fail)
@@ -817,7 +814,7 @@
info.ydpi = ydpi;
info.fps = 1e9 / hwConfig->getVsyncPeriod();
- const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(info.fps);
+ const auto offset = mPhaseConfiguration->getOffsetsForRefreshRate(info.fps);
info.appVsyncOffset = offset.late.app;
// This is how far in advance a buffer must be queued for
@@ -897,8 +894,8 @@
// DispSync model is locked.
mVSyncModulator->onRefreshRateChangeInitiated();
- mPhaseOffsets->setRefreshRateFps(refreshRate.fps);
- mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
+ mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
+ mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
}
mDesiredActiveConfigChanged = true;
@@ -951,8 +948,8 @@
auto refreshRate =
mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId);
- mPhaseOffsets->setRefreshRateFps(refreshRate.fps);
- mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
+ mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
+ mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
ATRACE_INT("ActiveConfigFPS", refreshRate.fps);
if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
@@ -969,8 +966,8 @@
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
auto refreshRate =
mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId);
- mPhaseOffsets->setRefreshRateFps(refreshRate.fps);
- mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
+ mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
+ mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
}
bool SurfaceFlinger::performSetActiveConfig() {
@@ -1698,10 +1695,8 @@
// We are storing the last 2 present fences. If sf's phase offset is to be
// woken up before the actual vsync but targeting the next vsync, we need to check
// fence N-2
- const sp<Fence>& fence =
- mVSyncModulator->getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
- ? mPreviousPresentFences[0]
- : mPreviousPresentFences[1];
+ const sp<Fence>& fence = mVSyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0]
+ : mPreviousPresentFences[1];
if (fence == Fence::NO_FENCE) {
return false;
@@ -1719,10 +1714,8 @@
mScheduler->getDisplayStatInfo(&stats);
const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime();
// Inflate the expected present time if we're targetting the next vsync.
- mExpectedPresentTime.store(mVSyncModulator->getOffsets().sf <
- mPhaseOffsets->getOffsetThresholdForNextVsync()
- ? presentTime
- : presentTime + stats.vsyncPeriod);
+ mExpectedPresentTime.store(
+ mVSyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod);
}
void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
@@ -1966,11 +1959,12 @@
nsecs_t compositeToPresentLatency) {
// Integer division and modulo round toward 0 not -inf, so we need to
// treat negative and positive offsets differently.
- nsecs_t idealLatency = (mPhaseOffsets->getCurrentSfOffset() > 0)
- ? (stats.vsyncPeriod - (mPhaseOffsets->getCurrentSfOffset() % stats.vsyncPeriod))
- : ((-mPhaseOffsets->getCurrentSfOffset()) % stats.vsyncPeriod);
+ nsecs_t idealLatency = (mPhaseConfiguration->getCurrentOffsets().late.sf > 0)
+ ? (stats.vsyncPeriod -
+ (mPhaseConfiguration->getCurrentOffsets().late.sf % stats.vsyncPeriod))
+ : ((-mPhaseConfiguration->getCurrentOffsets().late.sf) % stats.vsyncPeriod);
- // Just in case mPhaseOffsets->getCurrentSfOffset() == -vsyncInterval.
+ // Just in case mPhaseConfiguration->getCurrentOffsets().late.sf == -vsyncInterval.
if (idealLatency <= 0) {
idealLatency = stats.vsyncPeriod;
}
@@ -1979,8 +1973,8 @@
// composition and present times, which often have >1ms of jitter.
// Reducing jitter is important if an app attempts to extrapolate
// something (such as user input) to an accurate diasplay time.
- // Snapping also allows an app to precisely calculate mPhaseOffsets->getCurrentSfOffset()
- // with (presentLatency % interval).
+ // Snapping also allows an app to precisely calculate
+ // mPhaseConfiguration->getCurrentOffsets().late.sf with (presentLatency % interval).
nsecs_t bias = stats.vsyncPeriod / 2;
int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
nsecs_t snappedCompositeToPresentLatency =
@@ -2672,24 +2666,24 @@
currentConfig, HWC_POWER_MODE_OFF);
mRefreshRateStats->setConfigMode(currentConfig);
+ mPhaseConfiguration = getFactory().createPhaseConfiguration(*mRefreshRateConfigs);
+
// start the EventThread
mScheduler =
getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
*mRefreshRateConfigs, *this);
mAppConnectionHandle =
- mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
- mPhaseOffsets->getOffsetThresholdForNextVsync(),
+ mScheduler->createConnection("app", mPhaseConfiguration->getCurrentOffsets().late.app,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
- mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
- mPhaseOffsets->getOffsetThresholdForNextVsync(),
+ mScheduler->createConnection("sf", mPhaseConfiguration->getCurrentOffsets().late.sf,
[this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
mVSyncModulator.emplace(*mScheduler, mAppConnectionHandle, mSfConnectionHandle,
- mPhaseOffsets->getCurrentOffsets());
+ mPhaseConfiguration->getCurrentOffsets());
mRegionSamplingThread =
new RegionSamplingThread(*this, *mScheduler,
@@ -4090,7 +4084,7 @@
mRefreshRateStats->dump(result);
result.append("\n");
- mPhaseOffsets->dump(result);
+ mPhaseConfiguration->dump(result);
StringAppendF(&result,
" present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
dispSyncPresentTimeOffset, getVsyncPeriod());
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ec7f871..2f84b13 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1127,7 +1127,7 @@
scheduler::ConnectionHandle mSfConnectionHandle;
// Stores phase offsets configured per refresh rate.
- const std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
+ std::unique_ptr<scheduler::PhaseConfiguration> mPhaseConfiguration;
// Optional to defer construction until scheduler connections are created.
std::optional<scheduler::VSyncModulator> mVSyncModulator;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index bd4cdba..d5c2306 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -15,6 +15,7 @@
*/
#include <compositionengine/impl/CompositionEngine.h>
+#include <cutils/properties.h>
#include <ui/GraphicBuffer.h>
#include "BufferLayerConsumer.h"
@@ -51,16 +52,20 @@
}
std::unique_ptr<HWComposer> DefaultFactory::createHWComposer(const std::string& serviceName) {
- return std::make_unique<android::impl::HWComposer>(
- std::make_unique<Hwc2::impl::Composer>(serviceName));
+ return std::make_unique<android::impl::HWComposer>(serviceName);
}
std::unique_ptr<MessageQueue> DefaultFactory::createMessageQueue() {
return std::make_unique<android::impl::MessageQueue>();
}
-std::unique_ptr<scheduler::PhaseOffsets> DefaultFactory::createPhaseOffsets() {
- return std::make_unique<scheduler::impl::PhaseOffsets>();
+std::unique_ptr<scheduler::PhaseConfiguration> DefaultFactory::createPhaseConfiguration(
+ const scheduler::RefreshRateConfigs& refreshRateConfigs) {
+ if (property_get_bool("debug.sf.use_phase_offsets_as_durations", false)) {
+ return std::make_unique<scheduler::impl::PhaseDurations>(refreshRateConfigs);
+ } else {
+ return std::make_unique<scheduler::impl::PhaseOffsets>(refreshRateConfigs);
+ }
}
std::unique_ptr<Scheduler> DefaultFactory::createScheduler(
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 1a24448..36fae21 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -30,7 +30,8 @@
std::unique_ptr<EventControlThread> createEventControlThread(SetVSyncEnabled) override;
std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override;
std::unique_ptr<MessageQueue> createMessageQueue() override;
- std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override;
+ std::unique_ptr<scheduler::PhaseConfiguration> createPhaseConfiguration(
+ const scheduler::RefreshRateConfigs&) override;
std::unique_ptr<Scheduler> createScheduler(SetVSyncEnabled,
const scheduler::RefreshRateConfigs&,
ISchedulerCallback&) override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 0db941d..951bd09 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -56,7 +56,7 @@
} // namespace compositionengine
namespace scheduler {
-class PhaseOffsets;
+class PhaseConfiguration;
class RefreshRateConfigs;
} // namespace scheduler
@@ -74,7 +74,8 @@
virtual std::unique_ptr<EventControlThread> createEventControlThread(SetVSyncEnabled) = 0;
virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
- virtual std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() = 0;
+ virtual std::unique_ptr<scheduler::PhaseConfiguration> createPhaseConfiguration(
+ const scheduler::RefreshRateConfigs&) = 0;
virtual std::unique_ptr<Scheduler> createScheduler(SetVSyncEnabled,
const scheduler::RefreshRateConfigs&,
ISchedulerCallback&) = 0;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index ccfa6c5..68adbfc 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -45,6 +45,7 @@
"OneShotTimerTest.cpp",
"LayerHistoryTest.cpp",
"LayerMetadataTest.cpp",
+ "PhaseOffsetsTest.cpp",
"SchedulerTest.cpp",
"SchedulerUtilsTest.cpp",
"RefreshRateConfigsTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 76dea62..cce21ce 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -1154,8 +1154,10 @@
static void cleanup(CompositionTest* test) {
Layer::cleanupInjectedLayers(test);
- for (auto& hwcDisplay : test->mFlinger.mFakeHwcDisplays) {
- hwcDisplay->mutableLayers().clear();
+ for (auto& displayData : test->mFlinger.mutableHwcDisplayData()) {
+ static_cast<TestableSurfaceFlinger::HWC2Display*>(displayData.second.hwcDisplay.get())
+ ->mutableLayers()
+ .clear();
}
}
};
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index 0aa8cf5..2e705da 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -51,7 +51,6 @@
AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder;
static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms;
- static constexpr std::chrono::nanoseconds mOffsetThresholdForNextVsync = 16ms;
static constexpr int mIterations = 100;
};
@@ -79,8 +78,7 @@
void DispSyncSourceTest::createDispSyncSource() {
createDispSync();
- mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(),
- mOffsetThresholdForNextVsync.count(), true,
+ mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true,
"DispSyncSourceTest");
mDispSyncSource->setCallback(this);
}
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index da4eea0..b50ddf5 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -22,7 +22,7 @@
namespace android::scheduler {
-struct FakePhaseOffsets : PhaseOffsets {
+struct FakePhaseOffsets : PhaseConfiguration {
static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0;
Offsets getOffsetsForRefreshRate(float) const override { return getCurrentOffsets(); }
@@ -30,8 +30,7 @@
Offsets getCurrentOffsets() const override {
return {{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- FAKE_PHASE_OFFSET_NS};
+ {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
}
void setRefreshRateFps(float) override {}
diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
new file mode 100644
index 0000000..6360ec1
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "SchedulerUnittests"
+
+#include <gmock/gmock.h>
+#include <log/log.h>
+#include <thread>
+
+#include "Scheduler/PhaseOffsets.h"
+
+using namespace testing;
+
+namespace android {
+namespace scheduler {
+
+class TestablePhaseOffsetsAsDurations : public impl::PhaseDurations {
+public:
+ TestablePhaseOffsetsAsDurations(float currentFps, nsecs_t sfDuration, nsecs_t appDuration,
+ nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
+ nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration)
+ : impl::PhaseDurations({60.0f, 90.0f}, currentFps, sfDuration, appDuration,
+ sfEarlyDuration, appEarlyDuration, sfEarlyGlDuration,
+ appEarlyGlDuration) {}
+};
+
+class PhaseOffsetsTest : public testing::Test {
+protected:
+ PhaseOffsetsTest()
+ : mPhaseOffsets(60.0f, 10'500'000, 20'500'000, 16'000'000, 33'500'000, 13'500'000,
+ 38'000'000) {}
+
+ ~PhaseOffsetsTest() = default;
+
+ TestablePhaseOffsetsAsDurations mPhaseOffsets;
+};
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_60Hz) {
+ mPhaseOffsets.setRefreshRateFps(60.0f);
+ auto currentOffsets = mPhaseOffsets.getCurrentOffsets();
+ auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(60.0f);
+
+ EXPECT_EQ(currentOffsets, offsets);
+ EXPECT_EQ(offsets.late.sf, 6'166'667);
+
+ EXPECT_EQ(offsets.late.app, 2'333'334);
+
+ EXPECT_EQ(offsets.early.sf, 666'667);
+
+ EXPECT_EQ(offsets.early.app, 500'001);
+
+ EXPECT_EQ(offsets.earlyGl.sf, 3'166'667);
+
+ EXPECT_EQ(offsets.earlyGl.app, 15'166'668);
+}
+
+TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_90Hz) {
+ mPhaseOffsets.setRefreshRateFps(90.0f);
+ auto currentOffsets = mPhaseOffsets.getCurrentOffsets();
+ auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(90.0f);
+
+ EXPECT_EQ(currentOffsets, offsets);
+ EXPECT_EQ(offsets.late.sf, 611'111);
+
+ EXPECT_EQ(offsets.late.app, 2'333'333);
+
+ EXPECT_EQ(offsets.early.sf, -4'888'889);
+
+ EXPECT_EQ(offsets.early.app, 6'055'555);
+
+ EXPECT_EQ(offsets.earlyGl.sf, -2'388'889);
+
+ EXPECT_EQ(offsets.earlyGl.app, 4'055'555);
+}
+
+TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_DefaultOffsets) {
+ TestablePhaseOffsetsAsDurations phaseOffsetsWithDefaultValues(60.0f, -1, -1, -1, -1, -1, -1);
+
+ auto validateOffsets = [](auto& offsets) {
+ EXPECT_EQ(offsets.late.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.late.app, 1'000'000);
+
+ EXPECT_EQ(offsets.early.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.early.app, 1'000'000);
+
+ EXPECT_EQ(offsets.earlyGl.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.earlyGl.app, 1'000'000);
+ };
+
+ phaseOffsetsWithDefaultValues.setRefreshRateFps(90.0f);
+ auto currentOffsets = phaseOffsetsWithDefaultValues.getCurrentOffsets();
+ auto offsets = phaseOffsetsWithDefaultValues.getOffsetsForRefreshRate(90.0f);
+ EXPECT_EQ(currentOffsets, offsets);
+ validateOffsets(offsets);
+
+ phaseOffsetsWithDefaultValues.setRefreshRateFps(60.0f);
+ currentOffsets = phaseOffsetsWithDefaultValues.getCurrentOffsets();
+ offsets = phaseOffsetsWithDefaultValues.getOffsetsForRefreshRate(90.0f);
+ EXPECT_EQ(currentOffsets, offsets);
+ validateOffsets(offsets);
+}
+
+} // namespace
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index f057c98..b5245e2 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -79,7 +79,8 @@
return std::make_unique<android::impl::MessageQueue>();
}
- std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override {
+ std::unique_ptr<scheduler::PhaseConfiguration> createPhaseConfiguration(
+ const scheduler::RefreshRateConfigs& /*refreshRateConfigs*/) override {
return std::make_unique<scheduler::FakePhaseOffsets>();
}
@@ -207,6 +208,8 @@
scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats,
/*currentConfig=*/HwcConfigIndexType(0),
/*powerMode=*/HWC_POWER_MODE_OFF);
+ mFlinger->mPhaseConfiguration =
+ mFactory.createPhaseConfiguration(*mFlinger->mRefreshRateConfigs);
mScheduler =
new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread),
@@ -218,7 +221,7 @@
mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle,
mFlinger->mSfConnectionHandle,
- mFlinger->mPhaseOffsets->getCurrentOffsets());
+ mFlinger->mPhaseConfiguration->getCurrentOffsets());
}
void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); }
@@ -515,15 +518,13 @@
display->mutableIsConnected() = true;
display->setPowerMode(static_cast<HWC2::PowerMode>(mPowerMode));
- flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = display.get();
+ flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display);
if (mHwcDisplayType == HWC2::DisplayType::Physical) {
flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, mDisplayId);
(mIsPrimary ? flinger->mutableInternalHwcDisplayId()
: flinger->mutableExternalHwcDisplayId()) = mHwcDisplayId;
}
-
- flinger->mFakeHwcDisplays.push_back(std::move(display));
}
private:
@@ -632,9 +633,6 @@
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
TestableScheduler* mScheduler = nullptr;
-
- // We need to keep a reference to these so they are properly destroyed.
- std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays;
};
} // namespace android