Merge "Revert "Update statsd binary path for apex""
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 3713e87..e1a7bb8 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -701,11 +701,13 @@
if (delete_dir_contents_and_dir(path) != 0) {
res = error("Failed to delete " + path);
}
- destroy_app_current_profiles(packageName, userId);
- // TODO(calin): If the package is still installed by other users it's probably
- // beneficial to keep the reference profile around.
- // Verify if it's ok to do that.
- destroy_app_reference_profile(packageName);
+ if ((flags & FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
+ destroy_app_current_profiles(packageName, userId);
+ // TODO(calin): If the package is still installed by other users it's probably
+ // beneficial to keep the reference profile around.
+ // Verify if it's ok to do that.
+ destroy_app_reference_profile(packageName);
+ }
}
if (flags & FLAG_STORAGE_EXTERNAL) {
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
diff --git a/data/etc/android.hardware.tv.tuner.xml b/data/etc/android.hardware.tv.tuner.xml
new file mode 100644
index 0000000..bbf084f
--- /dev/null
+++ b/data/etc/android.hardware.tv.tuner.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<!-- This feature indicates that the device has tuner hardware and tuner HAL
+ implementation to support tuner operations. -->
+<permissions>
+ <feature name="android.hardware.tv.tuner" />
+</permissions>
diff --git a/headers/media_plugin/media/openmax/OMX_AudioExt.h b/headers/media_plugin/media/openmax/OMX_AudioExt.h
index 477faed..b66efce 100644
--- a/headers/media_plugin/media/openmax/OMX_AudioExt.h
+++ b/headers/media_plugin/media/openmax/OMX_AudioExt.h
@@ -116,6 +116,8 @@
OMX_S32 nEncodedTargetLevel; /**< Target reference level assumed at the encoder, between 0 and 127, -1 if unspecified */
OMX_S32 nPCMLimiterEnable; /**< Signal level limiting, 0 for disable, 1 for enable, -1 if unspecified */
OMX_S32 nDrcEffectType; /**< MPEG-D DRC effect type, between -1 and 6, -2 if unspecified */
+ OMX_S32 nDrcOutputLoudness; /**< MPEG-D DRC Output Loudness, between -1 and 231, -2 if unspecified */
+ OMX_S32 nDrcAlbumMode; /**< MPEG-D DRC Album Mode, between 0 and 1, -1 if unspecified */
} OMX_AUDIO_PARAM_ANDROID_AACDRCPRESENTATIONTYPE;
typedef struct OMX_AUDIO_PARAM_ANDROID_PROFILETYPE {
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index eeb8330..c30dcfe 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -425,12 +425,15 @@
* valid refresh rate for this device's display - e.g., it's fine to pass 30fps to a device that can
* only run the display at 60fps.
*
+ * |compatibility| The frame rate compatibility of this surface. The compatibility value may
+ * influence the system's choice of display frame rate. To specify a compatibility use the
+ * ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* enum.
+ *
* Available since API level 30.
*/
void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction,
- ASurfaceControl* surface_control,
- float frameRate)
- __INTRODUCED_IN(30);
+ ASurfaceControl* surface_control, float frameRate,
+ int8_t compatibility) __INTRODUCED_IN(30);
#endif // __ANDROID_API__ >= 30
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
index 7a77f6d..779ed41 100644
--- a/libs/binder/Static.cpp
+++ b/libs/binder/Static.cpp
@@ -64,13 +64,9 @@
int mFD;
};
-static LogTextOutput gLogTextOutput;
-static FdTextOutput gStdoutTextOutput(STDOUT_FILENO);
-static FdTextOutput gStderrTextOutput(STDERR_FILENO);
-
-TextOutput& alog(gLogTextOutput);
-TextOutput& aout(gStdoutTextOutput);
-TextOutput& aerr(gStderrTextOutput);
+TextOutput& alog(*new LogTextOutput());
+TextOutput& aout(*new FdTextOutput(STDOUT_FILENO));
+TextOutput& aerr(*new FdTextOutput(STDERR_FILENO));
// ------------ ProcessState.cpp
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
index e6b743b..33e4586 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -238,7 +238,9 @@
// ourselves. The defaults are harmless.
AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump);
#ifdef HAS_BINDER_SHELL_COMMAND
- AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
+ if (AIBinder_Class_setHandleShellCommand != nullptr) {
+ AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
+ }
#endif
return clazz;
}
diff --git a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
new file mode 100644
index 0000000..ac46cb8
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <android/binder_parcel.h>
+
+__BEGIN_DECLS
+
+/**
+ * Gets whether or not FDs are allowed by this AParcel
+ *
+ * \return true if FDs are allowed, false if they are not. That is
+ * if this returns false then AParcel_writeParcelFileDescriptor will
+ * return STATUS_FDS_NOT_ALLOWED.
+ */
+bool AParcel_getAllowFds(const AParcel*);
+
+__END_DECLS
\ No newline at end of file
diff --git a/libs/binder/ndk/include_platform/android/binder_shell.h b/libs/binder/ndk/include_platform/android/binder_shell.h
index 17b38b0..07d89e6 100644
--- a/libs/binder/ndk/include_platform/android/binder_shell.h
+++ b/libs/binder/ndk/include_platform/android/binder_shell.h
@@ -48,8 +48,7 @@
* \param handleShellCommand function to call when a shell transaction is
* received
*/
-void AIBinder_Class_setHandleShellCommand(AIBinder_Class* clazz,
- AIBinder_handleShellCommand handleShellCommand)
- __INTRODUCED_IN(30);
+__attribute__((weak)) void AIBinder_Class_setHandleShellCommand(
+ AIBinder_Class* clazz, AIBinder_handleShellCommand handleShellCommand) __INTRODUCED_IN(30);
__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 7e72f22..a9eba47 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -114,3 +114,8 @@
local:
*;
};
+
+LIBBINDER_NDK_PLATFORM {
+ global:
+ AParcel_getAllowFds;
+};
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index f0ea237..703ceae 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -15,6 +15,7 @@
*/
#include <android/binder_parcel.h>
+#include <android/binder_parcel_platform.h>
#include "parcel_internal.h"
#include "ibinder_internal.h"
@@ -645,4 +646,8 @@
return ReadArray<int8_t>(parcel, arrayData, allocator);
}
+bool AParcel_getAllowFds(const AParcel* parcel) {
+ return parcel->get()->allowFds();
+}
+
// @END
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 94ab9f0..e343df7 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -30,6 +30,7 @@
#include <private/binder/binder_module.h>
#include <sys/epoll.h>
+#include <sys/prctl.h>
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
@@ -107,6 +108,7 @@
if (pid == -1)
return pid;
if (pid == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
close(pipefd[0]);
execv(binderservername, childargv);
status = -errno;
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index b6b81bb..0b77ab3 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -156,11 +156,22 @@
static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
eventType.c_str(), eventName.c_str());
- int prog_fd = bpf_obj_get(path.c_str());
+ int prog_fd = bpfFdGet(path.c_str(), BPF_F_RDONLY);
if (prog_fd < 0) return false;
return bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) >= 0;
}
+static std::optional<uint32_t> getPolicyFreqIdx(uint32_t policy) {
+ auto path = StringPrintf("/sys/devices/system/cpu/cpufreq/policy%u/scaling_cur_freq",
+ gPolicyCpus[policy][0]);
+ auto freqVec = readNumbersFromFile(path);
+ if (!freqVec.has_value() || freqVec->size() != 1) return {};
+ for (uint32_t idx = 0; idx < gPolicyFreqs[policy].size(); ++idx) {
+ if ((*freqVec)[0] == gPolicyFreqs[policy][idx]) return idx + 1;
+ }
+ return {};
+}
+
// Start tracking and aggregating data to be reported by getUidCpuFreqTimes and getUidsCpuFreqTimes.
// Returns true on success, false otherwise.
// Tracking is active only once a live process has successfully called this function; if the calling
@@ -215,7 +226,9 @@
unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
if (policyFreqIdxFd < 0) return false;
for (uint32_t i = 0; i < gNPolicies; ++i) {
- if (writeToMapEntry(policyFreqIdxFd, &i, &zero, BPF_ANY)) return false;
+ auto freqIdx = getPolicyFreqIdx(i);
+ if (!freqIdx.has_value()) return false;
+ if (writeToMapEntry(policyFreqIdxFd, &i, &(*freqIdx), BPF_ANY)) return false;
}
gTracking = attachTracepointProgram("sched", "sched_switch") &&
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index acd833f..30e1351 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -101,6 +101,9 @@
mHeight(height),
mNextTransaction(nullptr) {
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ // since the adapter is in the client process, set dequeue timeout
+ // explicitly so that dequeueBuffer will block
+ mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());
int8_t disableTripleBuffer = property_get_bool("ro.sf.disable_triple_buffer", 0);
if (!disableTripleBuffer) {
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 2f27fd2..ce41eab 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1112,6 +1112,42 @@
}
return NO_ERROR;
}
+
+ virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
+ int8_t compatibility) {
+ Parcel data, reply;
+ status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed writing interface token: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = data.writeStrongBinder(IInterface::asBinder(surface));
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed writing strong binder: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = data.writeFloat(frameRate);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed writing float: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = data.writeByte(compatibility);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed writing byte: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply,
+ IBinder::FLAG_ONEWAY);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err);
+ return err;
+ }
+ return NO_ERROR;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -1877,6 +1913,36 @@
return setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ,
lightRadius);
}
+ case SET_FRAME_RATE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> binder;
+ status_t err = data.readStrongBinder(&binder);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed to read strong binder: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+ sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder);
+ if (!surface) {
+ ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+ float frameRate;
+ err = data.readFloat(&frameRate);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed to read float: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+ int8_t compatibility;
+ err = data.readByte(&compatibility);
+ if (err != NO_ERROR) {
+ ALOGE("setFrameRate: failed to read byte: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+ status_t result = setFrameRate(surface, frameRate, compatibility);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 5547efc..a9c9b74 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -24,6 +24,8 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/LayerState.h>
+#include <cmath>
+
namespace android {
status_t layer_state_t::write(Parcel& output) const
@@ -113,6 +115,7 @@
output.writeFloat(shadowRadius);
output.writeInt32(frameRateSelectionPriority);
output.writeFloat(frameRate);
+ output.writeByte(frameRateCompatibility);
return NO_ERROR;
}
@@ -194,6 +197,7 @@
shadowRadius = input.readFloat();
frameRateSelectionPriority = input.readInt32();
frameRate = input.readFloat();
+ frameRateCompatibility = input.readByte();
return NO_ERROR;
}
@@ -427,6 +431,7 @@
if (other.what & eFrameRateChanged) {
what |= eFrameRateChanged;
frameRate = other.frameRate;
+ frameRateCompatibility = other.frameRateCompatibility;
}
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
@@ -474,4 +479,21 @@
syncInputWindows = input.readBool();
}
+bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName) {
+ const char* functionName = inFunctionName != nullptr ? inFunctionName : "call";
+ int floatClassification = std::fpclassify(frameRate);
+ if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) {
+ ALOGE("%s failed - invalid frame rate %f", functionName, frameRate);
+ return false;
+ }
+
+ if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
+ compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE) {
+ ALOGE("%s failed - invalid compatibility value %d", functionName, compatibility);
+ return false;
+ }
+
+ return true;
+}
+
}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 278cc59..f911e70 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -43,6 +43,7 @@
#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
#include <private/gui/ComposerService.h>
namespace android {
@@ -1413,7 +1414,8 @@
int Surface::dispatchSetFrameRate(va_list args) {
float frameRate = static_cast<float>(va_arg(args, double));
- return setFrameRate(frameRate);
+ int8_t compatibility = static_cast<int8_t>(va_arg(args, int));
+ return setFrameRate(frameRate, compatibility);
}
int Surface::dispatchAddCancelInterceptor(va_list args) {
@@ -2222,11 +2224,15 @@
mSurfaceListener->onBuffersDiscarded(discardedBufs);
}
-status_t Surface::setFrameRate(float frameRate) {
+status_t Surface::setFrameRate(float frameRate, int8_t compatibility) {
ATRACE_CALL();
- ALOGV("Surface::setTargetFrameRate");
- Mutex::Autolock lock(mMutex);
- return mGraphicBufferProducer->setFrameRate(frameRate);
+ ALOGV("Surface::setFrameRate");
+
+ if (!ValidateFrameRate(frameRate, compatibility, "Surface::setFrameRate")) {
+ return BAD_VALUE;
+ }
+
+ return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility);
}
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index ff8b719..dc4860a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1387,14 +1387,19 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate(
- const sp<SurfaceControl>& sc, float frameRate) {
+ const sp<SurfaceControl>& sc, float frameRate, int8_t compatibility) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
+ if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate")) {
+ mStatus = BAD_VALUE;
+ return *this;
+ }
s->what |= layer_state_t::eFrameRateChanged;
s->frameRate = frameRate;
+ s->frameRateCompatibility = compatibility;
return *this;
}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e860f61..0659f0d 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -500,6 +500,12 @@
virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ,
float lightRadius) = 0;
+
+ /*
+ * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info.
+ */
+ virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
+ int8_t compatibility) = 0;
};
// ----------------------------------------------------------------------------
@@ -557,6 +563,7 @@
SET_AUTO_LOW_LATENCY_MODE,
GET_GAME_CONTENT_TYPE_SUPPORT,
SET_GAME_CONTENT_TYPE,
+ SET_FRAME_RATE,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 2d53b48..7e3d5d5 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -20,8 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/Errors.h>
-
+#include <android/native_window.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/ITransactionCompletedListener.h>
#include <math/mat4.h>
@@ -36,6 +35,7 @@
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Rotation.h>
+#include <utils/Errors.h>
namespace android {
@@ -135,7 +135,8 @@
colorSpaceAgnostic(false),
shadowRadius(0.0f),
frameRateSelectionPriority(-1),
- frameRate(0.0f) {
+ frameRate(0.0f),
+ frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -221,7 +222,9 @@
// Priority of the layer assigned by Window Manager.
int32_t frameRateSelectionPriority;
+ // Layer frame rate and compatibility. See ANativeWindow_setFrameRate().
float frameRate;
+ int8_t frameRateCompatibility;
};
struct ComposerState {
@@ -292,6 +295,12 @@
return compare_type(lhs.token, rhs.token);
}
+// Returns true if the frameRate and compatibility are valid values, false
+// othwerise. If either of the params are invalid, an error log is printed, and
+// functionName is added to the log to indicate which function call failed.
+// functionName can be null.
+bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName);
+
}; // namespace android
#endif // ANDROID_SF_LAYER_STATE_H
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 4a353fc..ad7cbfe 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -179,7 +179,7 @@
status_t getConsumerUsage(uint64_t* outUsage) const;
// See IGraphicBufferProducer::setFrameRate
- status_t setFrameRate(float frameRate);
+ status_t setFrameRate(float frameRate, int8_t compatibility);
protected:
virtual ~Surface();
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 27877bb..0cf141d 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -519,7 +519,8 @@
const Rect& source, const Rect& dst, int transform);
Transaction& setShadowRadius(const sp<SurfaceControl>& sc, float cornerRadius);
- Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate);
+ Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate,
+ int8_t compatibility);
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 70fd888..8c0f8f8 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -854,6 +854,11 @@
return NO_ERROR;
}
+ status_t setFrameRate(const sp<IGraphicBufferProducer>& /*surface*/, float /*frameRate*/,
+ int8_t /*compatibility*/) override {
+ return NO_ERROR;
+ }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 98b76fd..fd1793b 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -158,11 +158,11 @@
return query(window, NATIVE_WINDOW_DATASPACE);
}
-int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) {
- if (!window || !query(window, NATIVE_WINDOW_IS_VALID) || frameRate < 0) {
+int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) {
+ if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) {
return -EINVAL;
}
- return native_window_set_frame_rate(window, frameRate);
+ return native_window_set_frame_rate(window, frameRate, compatibility);
}
void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) {
@@ -335,7 +335,3 @@
void* data) {
return window->perform(window, NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR, interceptor, data);
}
-
-int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) {
- return query64(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID);
-}
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 4b426c5..59aa665 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -33,6 +33,7 @@
#ifndef ANDROID_NATIVE_WINDOW_H
#define ANDROID_NATIVE_WINDOW_H
+#include <stdint.h>
#include <sys/cdefs.h>
#include <android/data_space.h>
@@ -232,6 +233,24 @@
#if __ANDROID_API__ >= 30
+/* Parameter for ANativeWindow_setFrameRate */
+enum {
+ /**
+ * There are no inherent restrictions on the frame rate of this window.
+ */
+ ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT = 0,
+ /**
+ * This window is being used to display content with an inherently fixed
+ * frame rate, e.g. a video that has a specific frame rate. When the system
+ * selects a frame rate other than what the app requested, the app will need
+ * to do pull down or use some other technique to adapt to the system's
+ * frame rate. The user experience is likely to be worse (e.g. more frame
+ * stuttering) than it would be if the system had chosen the app's requested
+ * frame rate.
+ */
+ ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1
+};
+
/**
* Sets the intended frame rate for this window.
*
@@ -257,9 +276,15 @@
* refresh rate for this device's display - e.g., it's fine to pass 30fps to a
* device that can only run the display at 60fps.
*
- * \return 0 for success, -EINVAL if the window or frame rate are invalid.
+ * \param compatibility The frame rate compatibility of this window. The
+ * compatibility value may influence the system's choice of display refresh
+ * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info.
+ *
+ * \return 0 for success, -EINVAL if the window, frame rate, or compatibility
+ * value are invalid.
*/
-int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) __INTRODUCED_IN(30);
+int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility)
+ __INTRODUCED_IN(30);
/**
* Provides a hint to the window that buffers should be preallocated ahead of
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 02b886c..2d1354c 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -173,25 +173,22 @@
/**
* Retrieves how long it took for the last time a buffer was dequeued.
*
- * \return a negative value on error, otherwise returns the duration in
- * nanoseconds
+ * \return the dequeue duration in nanoseconds
*/
int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window);
/**
* Retrieves how long it took for the last time a buffer was queued.
*
- * \return a negative value on error, otherwise returns the duration in
- * nanoseconds.
+ * \return the queue duration in nanoseconds
*/
int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window);
/**
* Retrieves the system time in nanoseconds when the last time a buffer
- * was dequeued.
+ * started to be dequeued.
*
- * \return a negative value on error, otherwise returns the duration in
- * nanoseconds.
+ * \return the start time in nanoseconds
*/
int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window);
@@ -200,23 +197,14 @@
* made by the window will return -ETIMEDOUT after the timeout if the dequeue
* takes too long.
*
- * \return NO_ERROR on success, -errno on error.
+ * If the provided timeout is negative, hen this removes the previously configured
+ * timeout. The window then behaves as if ANativeWindow_setDequeueTimeout was
+ * never called.
+ *
+ * \return NO_ERROR on success
+ * \return BAD_VALUE if the dequeue timeout was unabled to be updated, as
+ * updating the dequeue timeout may change internals of the underlying window.
*/
int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout);
-/**
- * Provides a hint to the window that buffers should be preallocated ahead of
- * time. Note that the window implementation is not guaranteed to preallocate
- * any buffers, for instance if a private API disallows allocation of new
- * buffers. As such no success/error status is returned.
- */
-void ANativeWindow_allocateBuffers(ANativeWindow* window);
-
-/**
- * Retrieves an identifier for the next frame to be queued by this window.
- *
- * \return -errno on error, otherwise returns the next frame id.
- */
-int64_t ANativeWindow_getNextFrameId(ANativeWindow* window);
-
__END_DECLS
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index f686147..869ca9e 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1015,8 +1015,10 @@
return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation);
}
-static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate) {
- return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate);
+static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate,
+ int8_t compatibility) {
+ return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate,
+ (int)compatibility);
}
// ------------------------------------------------------------------------------------------------
@@ -1049,4 +1051,15 @@
outTransformMatrix);
}
+/**
+ * Retrieves an identifier for the next frame to be queued by this window.
+ *
+ * \return the next frame id.
+ */
+static inline int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) {
+ int64_t value;
+ window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, &value);
+ return value;
+}
+
__END_DECLS
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 154eb8e..1b5d20d 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -25,7 +25,6 @@
ANativeWindow_getLastDequeueDuration; # apex # introduced=30
ANativeWindow_getLastDequeueStartTime; # apex # introduced=30
ANativeWindow_getLastQueueDuration; # apex # introduced=30
- ANativeWindow_getNextFrameId; # apex # introduced=30
ANativeWindow_getWidth;
ANativeWindow_lock;
ANativeWindow_query; # llndk
@@ -46,9 +45,9 @@
ANativeWindow_setBuffersTimestamp; # llndk
ANativeWindow_setBuffersTransform;
ANativeWindow_setDequeueTimeout; # apex # introduced=30
+ ANativeWindow_setFrameRate; # introduced=30
ANativeWindow_setSharedBufferMode; # llndk
ANativeWindow_setSwapInterval; # llndk
- ANativeWindow_setFrameRate; # introduced=30
ANativeWindow_setUsage; # llndk
ANativeWindow_tryAllocateBuffers; # introduced=30
ANativeWindow_unlockAndPost;
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index ee06d93..f394635 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -15,12 +15,14 @@
*/
#include <ui/DebugUtils.h>
+#include <ui/DeviceProductInfo.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <android-base/stringprintf.h>
#include <string>
+using android::base::StringAppendF;
using android::base::StringPrintf;
using android::ui::ColorMode;
using android::ui::RenderIntent;
@@ -85,12 +87,11 @@
case HAL_DATASPACE_UNKNOWN:
// Fallthrough
default:
- return android::base::StringPrintf("Unknown deprecated dataspace code %d",
- dataspace);
+ return StringPrintf("Unknown deprecated dataspace code %d", dataspace);
}
}
- return android::base::StringPrintf("Unknown dataspace code %d", dataspaceSelect);
+ return StringPrintf("Unknown dataspace code %d", dataspaceSelect);
}
std::string decodeTransfer(android_dataspace dataspace) {
@@ -147,7 +148,7 @@
return std::string("STD-B67");
}
- return android::base::StringPrintf("Unknown dataspace transfer %d", dataspaceTransfer);
+ return StringPrintf("Unknown dataspace transfer %d", dataspaceTransfer);
}
std::string decodeRange(android_dataspace dataspace) {
@@ -187,16 +188,15 @@
return std::string("Extended range");
}
- return android::base::StringPrintf("Unknown dataspace range %d", dataspaceRange);
+ return StringPrintf("Unknown dataspace range %d", dataspaceRange);
}
std::string dataspaceDetails(android_dataspace dataspace) {
if (dataspace == 0) {
return "Default";
}
- return android::base::StringPrintf("%s %s %s", decodeStandard(dataspace).c_str(),
- decodeTransfer(dataspace).c_str(),
- decodeRange(dataspace).c_str());
+ return StringPrintf("%s %s %s", decodeStandard(dataspace).c_str(),
+ decodeTransfer(dataspace).c_str(), decodeRange(dataspace).c_str());
}
std::string decodeColorMode(ColorMode colorMode) {
@@ -244,7 +244,7 @@
return std::string("ColorMode::BT2100_HLG");
}
- return android::base::StringPrintf("Unknown color mode %d", colorMode);
+ return StringPrintf("Unknown color mode %d", colorMode);
}
std::string decodeColorTransform(android_color_transform colorTransform) {
@@ -271,7 +271,7 @@
return std::string("Correct tritanopia");
}
- return android::base::StringPrintf("Unknown color transform %d", colorTransform);
+ return StringPrintf("Unknown color transform %d", colorTransform);
}
// Converts a PixelFormat to a human-readable string. Max 11 chars.
@@ -303,7 +303,7 @@
case android::PIXEL_FORMAT_BGRA_8888:
return std::string("BGRA_8888");
default:
- return android::base::StringPrintf("Unknown %#08x", format);
+ return StringPrintf("Unknown %#08x", format);
}
}
@@ -324,3 +324,28 @@
std::string to_string(const android::Rect& rect) {
return StringPrintf("(%4d,%4d,%4d,%4d)", rect.left, rect.top, rect.right, rect.bottom);
}
+
+std::string toString(const android::DeviceProductInfo::ManufactureOrModelDate& date) {
+ using ModelYear = android::DeviceProductInfo::ModelYear;
+ using ManufactureYear = android::DeviceProductInfo::ManufactureYear;
+ using ManufactureWeekAndYear = android::DeviceProductInfo::ManufactureWeekAndYear;
+
+ if (const auto* model = std::get_if<ModelYear>(&date)) {
+ return StringPrintf("ModelYear{%d}", model->year);
+ } else if (const auto* manufacture = std::get_if<ManufactureYear>(&date)) {
+ return StringPrintf("ManufactureDate{year=%d}", manufacture->year);
+ } else if (const auto* manufacture = std::get_if<ManufactureWeekAndYear>(&date)) {
+ return StringPrintf("ManufactureDate{week=%d, year=%d}", manufacture->week,
+ manufacture->year);
+ } else {
+ LOG_FATAL("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate");
+ return {};
+ }
+}
+
+std::string toString(const android::DeviceProductInfo& info) {
+ return StringPrintf("DeviceProductInfo{name=%s, productId=%s, manufacturerPnpId=%s, "
+ "manufactureOrModelDate=%s}",
+ info.name.data(), info.productId.data(), info.manufacturerPnpId.data(),
+ toString(info.manufactureOrModelDate).c_str());
+}
diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h
index 92b2bfb..4685575 100644
--- a/libs/ui/include/ui/DebugUtils.h
+++ b/libs/ui/include/ui/DebugUtils.h
@@ -23,6 +23,7 @@
namespace android {
class Rect;
+struct DeviceProductInfo;
}
std::string decodeStandard(android_dataspace dataspace);
@@ -34,3 +35,4 @@
std::string decodePixelFormat(android::PixelFormat format);
std::string decodeRenderIntent(android::ui::RenderIntent renderIntent);
std::string to_string(const android::Rect& rect);
+std::string toString(const android::DeviceProductInfo&);
diff --git a/libs/ui/include/ui/DeviceProductInfo.h b/libs/ui/include/ui/DeviceProductInfo.h
new file mode 100644
index 0000000..c396e73
--- /dev/null
+++ b/libs/ui/include/ui/DeviceProductInfo.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#pragma once
+
+#include <array>
+#include <cstdint>
+#include <optional>
+#include <variant>
+
+namespace android {
+
+// NUL-terminated plug and play ID.
+using PnpId = std::array<char, 4>;
+
+// Product-specific information about the display or the directly connected device on the
+// display chain. For example, if the display is transitively connected, this field may contain
+// product information about the intermediate device.
+struct DeviceProductInfo {
+ static constexpr size_t TEXT_BUFFER_SIZE = 20;
+
+ struct ModelYear {
+ uint32_t year;
+ };
+
+ struct ManufactureYear : ModelYear {};
+
+ struct ManufactureWeekAndYear : ManufactureYear {
+ // 1-base week number. Week numbering may not be consistent between manufacturers.
+ uint8_t week;
+ };
+
+ // Display name.
+ std::array<char, TEXT_BUFFER_SIZE> name;
+
+ // Manufacturer Plug and Play ID.
+ PnpId manufacturerPnpId;
+
+ // Manufacturer product ID.
+ std::array<char, TEXT_BUFFER_SIZE> productId;
+
+ using ManufactureOrModelDate = std::variant<ModelYear, ManufactureYear, ManufactureWeekAndYear>;
+ ManufactureOrModelDate manufactureOrModelDate;
+};
+
+} // namespace android
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 69f86d3..897060c 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -16,8 +16,11 @@
#pragma once
+#include <optional>
#include <type_traits>
+#include <ui/DeviceProductInfo.h>
+
namespace android {
enum class DisplayConnectionType { Internal, External };
@@ -27,6 +30,7 @@
DisplayConnectionType connectionType = DisplayConnectionType::Internal;
float density = 0.f;
bool secure = false;
+ std::optional<DeviceProductInfo> deviceProductInfo;
};
static_assert(std::is_trivially_copyable_v<DisplayInfo>);
diff --git a/libs/ui/include_vndk/ui/DeviceProductInfo.h b/libs/ui/include_vndk/ui/DeviceProductInfo.h
new file mode 120000
index 0000000..c8f1d43
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DeviceProductInfo.h
@@ -0,0 +1 @@
+../../include/ui/DeviceProductInfo.h
\ No newline at end of file
diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp
index 385b981..066a816 100644
--- a/services/inputflinger/benchmarks/Android.bp
+++ b/services/inputflinger/benchmarks/Android.bp
@@ -7,6 +7,7 @@
shared_libs: [
"libbase",
"libbinder",
+ "libcrypto",
"libcutils",
"libinput",
"libinputflinger_base",
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index b723654..c4b3789 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -57,6 +57,32 @@
}
return StringPrintf("%" PRId32, action);
}
+VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry) {
+ return {{VerifiedInputEvent::Type::KEY, entry.deviceId, entry.eventTime, entry.source,
+ entry.displayId},
+ entry.action,
+ entry.downTime,
+ entry.flags & VERIFIED_KEY_EVENT_FLAGS,
+ entry.keyCode,
+ entry.scanCode,
+ entry.metaState,
+ entry.repeatCount};
+}
+
+VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry) {
+ const float rawX = entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
+ const float rawY = entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
+ const int actionMasked = entry.action & AMOTION_EVENT_ACTION_MASK;
+ return {{VerifiedInputEvent::Type::MOTION, entry.deviceId, entry.eventTime, entry.source,
+ entry.displayId},
+ rawX,
+ rawY,
+ actionMasked,
+ entry.downTime,
+ entry.flags & VERIFIED_MOTION_EVENT_FLAGS,
+ entry.metaState,
+ entry.buttonState};
+}
// --- EventEntry ---
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index e8c37f0..b5b61cc 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -220,6 +220,9 @@
static uint32_t nextSeq();
};
+VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry);
+VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry);
+
class InputDispatcher;
// A command entry captures state and behavior for an action to be performed in the
// dispatch loop after the initial processing has taken place. It is essentially
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 75bc0aa..f9a86dd 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2433,12 +2433,16 @@
switch (eventEntry->type) {
case EventEntry::Type::KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
+ VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEntry(*keyEntry);
+ verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_KEY_EVENT_FLAGS;
+ verifiedEvent.action = dispatchEntry->resolvedAction;
+ std::array<uint8_t, 32> hmac = mHmacKeyManager.sign(verifiedEvent);
// Publish the key event.
status = connection->inputPublisher
.publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId,
keyEntry->source, keyEntry->displayId,
- INVALID_HMAC, dispatchEntry->resolvedAction,
+ std::move(hmac), dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags, keyEntry->keyCode,
keyEntry->scanCode, keyEntry->metaState,
keyEntry->repeatCount, keyEntry->downTime,
@@ -2482,12 +2486,18 @@
usingCoords = scaledCoords;
}
}
+ VerifiedMotionEvent verifiedEvent =
+ verifiedMotionEventFromMotionEntry(*motionEntry);
+ verifiedEvent.actionMasked =
+ dispatchEntry->resolvedAction & AMOTION_EVENT_ACTION_MASK;
+ verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS;
+ std::array<uint8_t, 32> hmac = mHmacKeyManager.sign(verifiedEvent);
// Publish the motion event.
status = connection->inputPublisher
.publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId,
motionEntry->source, motionEntry->displayId,
- INVALID_HMAC, dispatchEntry->resolvedAction,
+ std::move(hmac), dispatchEntry->resolvedAction,
motionEntry->actionButton,
dispatchEntry->resolvedFlags,
motionEntry->edgeFlags, motionEntry->metaState,
@@ -3392,7 +3402,36 @@
}
std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const InputEvent& event) {
- return nullptr;
+ std::array<uint8_t, 32> calculatedHmac;
+ std::unique_ptr<VerifiedInputEvent> result;
+ switch (event.getType()) {
+ case AINPUT_EVENT_TYPE_KEY: {
+ const KeyEvent& keyEvent = static_cast<const KeyEvent&>(event);
+ VerifiedKeyEvent verifiedKeyEvent = verifiedKeyEventFromKeyEvent(keyEvent);
+ result = std::make_unique<VerifiedKeyEvent>(verifiedKeyEvent);
+ calculatedHmac = mHmacKeyManager.sign(verifiedKeyEvent);
+ break;
+ }
+ case AINPUT_EVENT_TYPE_MOTION: {
+ const MotionEvent& motionEvent = static_cast<const MotionEvent&>(event);
+ VerifiedMotionEvent verifiedMotionEvent =
+ verifiedMotionEventFromMotionEvent(motionEvent);
+ result = std::make_unique<VerifiedMotionEvent>(verifiedMotionEvent);
+ calculatedHmac = mHmacKeyManager.sign(verifiedMotionEvent);
+ break;
+ }
+ default: {
+ ALOGE("Cannot verify events of type %" PRId32, event.getType());
+ return nullptr;
+ }
+ }
+ if (calculatedHmac == INVALID_HMAC) {
+ return nullptr;
+ }
+ if (calculatedHmac != event.getHmac()) {
+ return nullptr;
+ }
+ return result;
}
bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index ded59a5..482133e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -217,6 +217,8 @@
// the pointer stream in order to claim it for a system gesture.
std::unordered_map<int32_t, std::vector<Monitor>> mGestureMonitorsByDisplay GUARDED_BY(mLock);
+ HmacKeyManager mHmacKeyManager;
+
// Event injection and synchronization.
std::condition_variable mInjectionResultAvailable;
bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 3e23fa6..8327ed8 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -62,11 +62,7 @@
} // release lock
}
-InputReader::~InputReader() {
- for (auto& devicePair : mDevices) {
- delete devicePair.second;
- }
-}
+InputReader::~InputReader() {}
status_t InputReader::start() {
if (mThread) {
@@ -198,7 +194,8 @@
uint32_t classes = mEventHub->getDeviceClasses(deviceId);
int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
- InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
+ std::shared_ptr<InputDevice> device =
+ createDeviceLocked(deviceId, controllerNumber, identifier, classes);
device->configure(when, &mConfig, 0);
device->reset(when);
@@ -210,7 +207,7 @@
device->getSources());
}
- mDevices.insert({deviceId, device});
+ mDevices.emplace(deviceId, device);
bumpGenerationLocked();
if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
@@ -225,7 +222,7 @@
return;
}
- InputDevice* device = deviceIt->second;
+ std::shared_ptr<InputDevice> device = std::move(deviceIt->second);
mDevices.erase(deviceIt);
bumpGenerationLocked();
@@ -242,13 +239,13 @@
}
device->reset(when);
- delete device;
}
-InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier,
- uint32_t classes) {
- InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
+std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
+ int32_t deviceId, int32_t controllerNumber, const InputDeviceIdentifier& identifier,
+ uint32_t classes) {
+ std::shared_ptr<InputDevice> device =
+ std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
controllerNumber, identifier, classes);
device->populateMappers();
return device;
@@ -262,7 +259,7 @@
return;
}
- InputDevice* device = deviceIt->second;
+ std::shared_ptr<InputDevice>& device = deviceIt->second;
if (device->isIgnored()) {
// ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
@@ -273,7 +270,7 @@
void InputReader::timeoutExpiredLocked(nsecs_t when) {
for (auto& devicePair : mDevices) {
- InputDevice* device = devicePair.second;
+ std::shared_ptr<InputDevice>& device = devicePair.second;
if (!device->isIgnored()) {
device->timeoutExpired(when);
}
@@ -302,7 +299,7 @@
mEventHub->requestReopenDevices();
} else {
for (auto& devicePair : mDevices) {
- InputDevice* device = devicePair.second;
+ std::shared_ptr<InputDevice>& device = devicePair.second;
device->configure(now, &mConfig, changes);
}
}
@@ -313,7 +310,7 @@
mGlobalMetaState = 0;
for (auto& devicePair : mDevices) {
- InputDevice* device = devicePair.second;
+ std::shared_ptr<InputDevice>& device = devicePair.second;
mGlobalMetaState |= device->getMetaState();
}
}
@@ -328,7 +325,7 @@
void InputReader::getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices) {
for (auto& devicePair : mDevices) {
- InputDevice* device = devicePair.second;
+ std::shared_ptr<InputDevice>& device = devicePair.second;
if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) {
InputDeviceInfo info;
device->getDeviceInfo(&info);
@@ -339,7 +336,7 @@
void InputReader::dispatchExternalStylusState(const StylusState& state) {
for (auto& devicePair : mDevices) {
- InputDevice* device = devicePair.second;
+ std::shared_ptr<InputDevice>& device = devicePair.second;
device->updateExternalStylusState(state);
}
}
@@ -361,7 +358,7 @@
void InputReader::fadePointerLocked() {
for (auto& devicePair : mDevices) {
- InputDevice* device = devicePair.second;
+ std::shared_ptr<InputDevice>& device = devicePair.second;
device->fadePointer();
}
}
@@ -386,7 +383,7 @@
outInputDevices.clear();
for (auto& devicePair : mDevices) {
- InputDevice* device = devicePair.second;
+ std::shared_ptr<InputDevice>& device = devicePair.second;
if (!device->isIgnored()) {
InputDeviceInfo info;
device->getDeviceInfo(&info);
@@ -419,18 +416,18 @@
if (deviceId >= 0) {
auto deviceIt = mDevices.find(deviceId);
if (deviceIt != mDevices.end()) {
- InputDevice* device = deviceIt->second;
+ std::shared_ptr<InputDevice>& device = deviceIt->second;
if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
- result = (device->*getStateFunc)(sourceMask, code);
+ result = (device.get()->*getStateFunc)(sourceMask, code);
}
}
} else {
for (auto& devicePair : mDevices) {
- InputDevice* device = devicePair.second;
+ std::shared_ptr<InputDevice>& device = devicePair.second;
if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
// If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
// value. Otherwise, return AKEY_STATE_UP as long as one device reports it.
- int32_t currentResult = (device->*getStateFunc)(sourceMask, code);
+ int32_t currentResult = (device.get()->*getStateFunc)(sourceMask, code);
if (currentResult >= AKEY_STATE_DOWN) {
return currentResult;
} else if (currentResult == AKEY_STATE_UP) {
@@ -449,7 +446,7 @@
return;
}
- InputDevice* device = deviceIt->second;
+ std::shared_ptr<InputDevice>& device = deviceIt->second;
if (device->isIgnored()) {
return;
}
@@ -472,14 +469,14 @@
if (deviceId >= 0) {
auto deviceIt = mDevices.find(deviceId);
if (deviceIt != mDevices.end()) {
- InputDevice* device = deviceIt->second;
+ std::shared_ptr<InputDevice>& device = deviceIt->second;
if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
}
}
} else {
for (auto& devicePair : mDevices) {
- InputDevice* device = devicePair.second;
+ std::shared_ptr<InputDevice>& device = devicePair.second;
if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
result |= device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
}
@@ -506,7 +503,7 @@
AutoMutex _l(mLock);
auto deviceIt = mDevices.find(deviceId);
if (deviceIt != mDevices.end()) {
- InputDevice* device = deviceIt->second;
+ std::shared_ptr<InputDevice>& device = deviceIt->second;
device->vibrate(pattern, patternSize, repeat, token);
}
}
@@ -516,7 +513,7 @@
auto deviceIt = mDevices.find(deviceId);
if (deviceIt != mDevices.end()) {
- InputDevice* device = deviceIt->second;
+ std::shared_ptr<InputDevice>& device = deviceIt->second;
device->cancelVibrate(token);
}
}
@@ -526,7 +523,7 @@
auto deviceIt = mDevices.find(deviceId);
if (deviceIt != mDevices.end()) {
- InputDevice* device = deviceIt->second;
+ std::shared_ptr<InputDevice>& device = deviceIt->second;
return device->isEnabled();
}
ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId);
@@ -542,7 +539,7 @@
return false;
}
- InputDevice* device = deviceIt->second;
+ std::shared_ptr<InputDevice>& device = deviceIt->second;
if (!device->isEnabled()) {
ALOGW("Ignoring disabled device %s", device->getName().c_str());
return false;
@@ -571,7 +568,7 @@
dump += "Input Reader State:\n";
for (const auto& devicePair : mDevices) {
- InputDevice* const device = devicePair.second;
+ const std::shared_ptr<InputDevice>& device = devicePair.second;
device->dump(dump);
}
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index cf1af04..4f5d2ea 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -84,9 +84,10 @@
protected:
// These members are protected so they can be instrumented by test cases.
- virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier,
- uint32_t classes);
+ virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t deviceId,
+ int32_t controllerNumber,
+ const InputDeviceIdentifier& identifier,
+ uint32_t classes);
// With each iteration of the loop, InputReader reads and processes one incoming message from
// the EventHub.
@@ -138,7 +139,7 @@
static const int EVENT_BUFFER_SIZE = 256;
RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
- std::unordered_map<int32_t /*deviceId*/, InputDevice*> mDevices;
+ std::unordered_map<int32_t /*deviceId*/, std::shared_ptr<InputDevice>> mDevices;
// low-level input event decoding and device management
void processEventsLocked(const RawEvent* rawEvents, size_t count);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c4092cd..2fb1b65 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1398,6 +1398,44 @@
window->assertNoEvents();
}
+TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ window->setFocus(true);
+
+ mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+ window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
+ mDispatcher->notifyKey(&keyArgs);
+
+ InputEvent* event = window->consume();
+ ASSERT_NE(event, nullptr);
+
+ std::unique_ptr<VerifiedInputEvent> verified = mDispatcher->verifyInputEvent(*event);
+ ASSERT_NE(verified, nullptr);
+ ASSERT_EQ(verified->type, VerifiedInputEvent::Type::KEY);
+
+ ASSERT_EQ(keyArgs.eventTime, verified->eventTimeNanos);
+ ASSERT_EQ(keyArgs.deviceId, verified->deviceId);
+ ASSERT_EQ(keyArgs.source, verified->source);
+ ASSERT_EQ(keyArgs.displayId, verified->displayId);
+
+ const VerifiedKeyEvent& verifiedKey = static_cast<const VerifiedKeyEvent&>(*verified);
+
+ ASSERT_EQ(keyArgs.action, verifiedKey.action);
+ ASSERT_EQ(keyArgs.downTime, verifiedKey.downTimeNanos);
+ ASSERT_EQ(keyArgs.eventTime, verifiedKey.eventTimeNanos);
+ ASSERT_EQ(keyArgs.flags & VERIFIED_KEY_EVENT_FLAGS, verifiedKey.flags);
+ ASSERT_EQ(keyArgs.keyCode, verifiedKey.keyCode);
+ ASSERT_EQ(keyArgs.scanCode, verifiedKey.scanCode);
+ ASSERT_EQ(keyArgs.metaState, verifiedKey.metaState);
+ ASSERT_EQ(0, verifiedKey.repeatCount);
+}
+
/* Test InputDispatcher for MultiDisplay */
class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
public:
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 01bd9db..b7f9942 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -18,12 +18,15 @@
#include <InputDevice.h>
#include <InputMapper.h>
#include <InputReader.h>
+#include <InputReaderBase.h>
+#include <InputReaderFactory.h>
#include <KeyboardInputMapper.h>
#include <MultiTouchInputMapper.h>
#include <SingleTouchInputMapper.h>
#include <SwitchInputMapper.h>
#include <TestInputListener.h>
#include <TouchInputMapper.h>
+#include <UinputDevice.h>
#include <android-base/thread_annotations.h>
#include <gtest/gtest.h>
@@ -187,17 +190,19 @@
}
void assertInputDevicesChanged() {
- std::unique_lock<std::mutex> lock(mLock);
- base::ScopedLockAssertion assumeLocked(mLock);
+ waitForInputDevices([](bool devicesChanged) {
+ if (!devicesChanged) {
+ FAIL() << "Timed out waiting for notifyInputDevicesChanged() to be called.";
+ }
+ });
+ }
- const bool devicesChanged =
- mDevicesChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) {
- return mInputDevicesChanged;
- });
- if (!devicesChanged) {
- FAIL() << "Timed out waiting for notifyInputDevicesChanged() to be called.";
- }
- mInputDevicesChanged = false;
+ void assertInputDevicesNotChanged() {
+ waitForInputDevices([](bool devicesChanged) {
+ if (devicesChanged) {
+ FAIL() << "Expected notifyInputDevicesChanged() to not be called.";
+ }
+ });
}
virtual void clearViewports() {
@@ -331,6 +336,18 @@
virtual std::string getDeviceAlias(const InputDeviceIdentifier&) {
return "";
}
+
+ void waitForInputDevices(std::function<void(bool)> processDevicesChanged) {
+ std::unique_lock<std::mutex> lock(mLock);
+ base::ScopedLockAssertion assumeLocked(mLock);
+
+ const bool devicesChanged =
+ mDevicesChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) {
+ return mInputDevicesChanged;
+ });
+ ASSERT_NO_FATAL_FAILURE(processDevicesChanged(devicesChanged));
+ mInputDevicesChanged = false;
+ }
};
// --- FakeEventHub ---
@@ -1091,7 +1108,7 @@
// --- InstrumentedInputReader ---
class InstrumentedInputReader : public InputReader {
- InputDevice* mNextDevice;
+ std::shared_ptr<InputDevice> mNextDevice;
public:
InstrumentedInputReader(std::shared_ptr<EventHubInterface> eventHub,
@@ -1099,33 +1116,31 @@
const sp<InputListenerInterface>& listener)
: InputReader(eventHub, policy, listener), mNextDevice(nullptr) {}
- virtual ~InstrumentedInputReader() {
- if (mNextDevice) {
- delete mNextDevice;
- }
- }
+ virtual ~InstrumentedInputReader() {}
- void setNextDevice(InputDevice* device) { mNextDevice = device; }
+ void setNextDevice(std::shared_ptr<InputDevice> device) { mNextDevice = device; }
- InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const std::string& name,
- uint32_t classes, const std::string& location = "") {
+ std::shared_ptr<InputDevice> newDevice(int32_t deviceId, int32_t controllerNumber,
+ const std::string& name, uint32_t classes,
+ const std::string& location = "") {
InputDeviceIdentifier identifier;
identifier.name = name;
identifier.location = location;
int32_t generation = deviceId + 1;
- return new InputDevice(&mContext, deviceId, generation, controllerNumber, identifier,
- classes);
+ return std::make_shared<InputDevice>(&mContext, deviceId, generation, controllerNumber,
+ identifier, classes);
}
// Make the protected loopOnce method accessible to tests.
using InputReader::loopOnce;
protected:
- virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier,
- uint32_t classes) {
+ virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t deviceId,
+ int32_t controllerNumber,
+ const InputDeviceIdentifier& identifier,
+ uint32_t classes) {
if (mNextDevice) {
- InputDevice* device = mNextDevice;
+ std::shared_ptr<InputDevice> device(mNextDevice);
mNextDevice = nullptr;
return device;
}
@@ -1368,7 +1383,8 @@
const std::string& name, uint32_t classes,
uint32_t sources,
const PropertyMap* configuration) {
- InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes);
+ std::shared_ptr<InputDevice> device =
+ mReader->newDevice(deviceId, controllerNumber, name, classes);
FakeInputMapper& mapper = device->addMapper<FakeInputMapper>(sources);
mReader->setNextDevice(device);
addDevice(deviceId, name, classes, configuration);
@@ -1404,7 +1420,8 @@
TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
constexpr int32_t deviceId = 1;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
+ std::shared_ptr<InputDevice> device =
+ mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
device->addMapper<FakeInputMapper>(AINPUT_SOURCE_KEYBOARD);
mReader->setNextDevice(device);
@@ -1584,7 +1601,8 @@
TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) {
constexpr int32_t deviceId = 1;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
+ std::shared_ptr<InputDevice> device =
+ mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
device->addMapper<FakeInputMapper>(AINPUT_SOURCE_KEYBOARD);
mReader->setNextDevice(device);
@@ -1617,8 +1635,8 @@
constexpr int32_t deviceId = 1;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
const char* DEVICE_LOCATION = "USB1";
- InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass,
- DEVICE_LOCATION);
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, 0 /*controllerNumber*/,
+ "fake", deviceClass, DEVICE_LOCATION);
FakeInputMapper& mapper = device->addMapper<FakeInputMapper>(AINPUT_SOURCE_TOUCHSCREEN);
mReader->setNextDevice(device);
@@ -1655,6 +1673,119 @@
ASSERT_FALSE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID));
}
+// --- InputReaderIntegrationTest ---
+
+// These tests create and interact with the InputReader only through its interface.
+// The InputReader is started during SetUp(), which starts its processing in its own
+// thread. The tests use linux uinput to emulate input devices.
+// NOTE: Interacting with the physical device while these tests are running may cause
+// the tests to fail.
+class InputReaderIntegrationTest : public testing::Test {
+protected:
+ sp<TestInputListener> mTestListener;
+ sp<FakeInputReaderPolicy> mFakePolicy;
+ sp<InputReaderInterface> mReader;
+
+ virtual void SetUp() override {
+ mFakePolicy = new FakeInputReaderPolicy();
+ mTestListener = new TestInputListener();
+
+ mReader = createInputReader(mFakePolicy, mTestListener);
+ ASSERT_EQ(mReader->start(), OK);
+
+ // Since this test is run on a real device, all the input devices connected
+ // to the test device will show up in mReader. We wait for those input devices to
+ // show up before beginning the tests.
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
+ }
+
+ virtual void TearDown() override {
+ ASSERT_EQ(mReader->stop(), OK);
+ mTestListener.clear();
+ mFakePolicy.clear();
+ }
+};
+
+TEST_F(InputReaderIntegrationTest, TestInvalidDevice) {
+ // An invalid input device that is only used for this test.
+ class InvalidUinputDevice : public UinputDevice {
+ public:
+ InvalidUinputDevice() : UinputDevice("Invalid Device") {}
+
+ private:
+ void configureDevice(int fd, uinput_user_dev* device) override {}
+ };
+
+ const size_t numDevices = mFakePolicy->getInputDevices().size();
+
+ // UinputDevice does not set any event or key bits, so InputReader should not
+ // consider it as a valid device.
+ std::unique_ptr<UinputDevice> invalidDevice = createUinputDevice<InvalidUinputDevice>();
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesNotChanged());
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasNotCalled());
+ ASSERT_EQ(numDevices, mFakePolicy->getInputDevices().size());
+
+ invalidDevice.reset();
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesNotChanged());
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasNotCalled());
+ ASSERT_EQ(numDevices, mFakePolicy->getInputDevices().size());
+}
+
+TEST_F(InputReaderIntegrationTest, AddNewDevice) {
+ const size_t initialNumDevices = mFakePolicy->getInputDevices().size();
+
+ std::unique_ptr<UinputHomeKey> keyboard = createUinputDevice<UinputHomeKey>();
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
+ ASSERT_EQ(initialNumDevices + 1, mFakePolicy->getInputDevices().size());
+
+ // Find the test device by its name.
+ std::vector<InputDeviceInfo> inputDevices;
+ mReader->getInputDevices(inputDevices);
+ InputDeviceInfo* keyboardInfo = nullptr;
+ const char* keyboardName = keyboard->getName();
+ for (unsigned int i = 0; i < initialNumDevices + 1; i++) {
+ if (!strcmp(inputDevices[i].getIdentifier().name.c_str(), keyboardName)) {
+ keyboardInfo = &inputDevices[i];
+ break;
+ }
+ }
+ ASSERT_NE(keyboardInfo, nullptr);
+ ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, keyboardInfo->getKeyboardType());
+ ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyboardInfo->getSources());
+ ASSERT_EQ(0U, keyboardInfo->getMotionRanges().size());
+
+ keyboard.reset();
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
+ ASSERT_EQ(initialNumDevices, mFakePolicy->getInputDevices().size());
+}
+
+TEST_F(InputReaderIntegrationTest, SendsEventsToInputListener) {
+ std::unique_ptr<UinputHomeKey> keyboard = createUinputDevice<UinputHomeKey>();
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
+
+ NotifyConfigurationChangedArgs configChangedArgs;
+ ASSERT_NO_FATAL_FAILURE(
+ mTestListener->assertNotifyConfigurationChangedWasCalled(&configChangedArgs));
+ uint32_t prevSequenceNum = configChangedArgs.sequenceNum;
+ nsecs_t prevTimestamp = configChangedArgs.eventTime;
+
+ NotifyKeyArgs keyArgs;
+ keyboard->pressAndReleaseHomeKey();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs));
+ ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action);
+ ASSERT_LT(prevSequenceNum, keyArgs.sequenceNum);
+ prevSequenceNum = keyArgs.sequenceNum;
+ ASSERT_LE(prevTimestamp, keyArgs.eventTime);
+ prevTimestamp = keyArgs.eventTime;
+
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs));
+ ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action);
+ ASSERT_LT(prevSequenceNum, keyArgs.sequenceNum);
+ ASSERT_LE(prevTimestamp, keyArgs.eventTime);
+}
// --- InputDeviceTest ---
class InputDeviceTest : public testing::Test {
@@ -1671,7 +1802,7 @@
sp<TestInputListener> mFakeListener;
FakeInputReaderContext* mFakeContext;
- InputDevice* mDevice;
+ std::shared_ptr<InputDevice> mDevice;
virtual void SetUp() override {
mFakeEventHub = std::make_unique<FakeEventHub>();
@@ -1683,13 +1814,13 @@
InputDeviceIdentifier identifier;
identifier.name = DEVICE_NAME;
identifier.location = DEVICE_LOCATION;
- mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
- DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
+ mDevice =
+ std::make_shared<InputDevice>(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
+ DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
}
virtual void TearDown() override {
- delete mDevice;
-
+ mDevice = nullptr;
delete mFakeContext;
mFakeListener.clear();
mFakePolicy.clear();
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 5246c78..532a2e5 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -33,6 +33,10 @@
"-fvisibility=hidden"
],
+ header_libs: [
+ "android.hardware.sensors@2.X-shared-utils",
+ ],
+
shared_libs: [
"libcutils",
"libhardware",
@@ -49,9 +53,12 @@
"libfmq",
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
+ "android.hardware.sensors@2.1",
],
- static_libs: ["android.hardware.sensors@1.0-convert"],
+ static_libs: [
+ "android.hardware.sensors@1.0-convert",
+ ],
generated_headers: ["framework-cppstream-protos"],
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 33f940f..3b68e0e 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -16,8 +16,10 @@
#include "SensorDevice.h"
-#include "android/hardware/sensors/2.0/ISensorsCallback.h"
#include "android/hardware/sensors/2.0/types.h"
+#include "android/hardware/sensors/2.1/ISensorsCallback.h"
+#include "android/hardware/sensors/2.1/types.h"
+#include "convertV2_1.h"
#include "SensorService.h"
#include <android-base/logging.h>
@@ -35,9 +37,15 @@
using namespace android::hardware::sensors;
using namespace android::hardware::sensors::V1_0;
using namespace android::hardware::sensors::V1_0::implementation;
-using android::hardware::sensors::V2_0::ISensorsCallback;
using android::hardware::sensors::V2_0::EventQueueFlagBits;
using android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using android::hardware::sensors::V2_1::ISensorsCallback;
+using android::hardware::sensors::V2_1::implementation::convertToOldSensorInfo;
+using android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos;
+using android::hardware::sensors::V2_1::implementation::convertToNewEvents;
+using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV1_0;
+using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_0;
+using android::hardware::sensors::V2_1::implementation::ISensorsWrapperV2_1;
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
@@ -87,11 +95,19 @@
struct SensorsCallback : public ISensorsCallback {
using Result = ::android::hardware::sensors::V1_0::Result;
- Return<void> onDynamicSensorsConnected(
+ using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo;
+
+ Return<void> onDynamicSensorsConnected_2_1(
const hidl_vec<SensorInfo> &dynamicSensorsAdded) override {
return SensorDevice::getInstance().onDynamicSensorsConnected(dynamicSensorsAdded);
}
+ Return<void> onDynamicSensorsConnected(
+ const hidl_vec<V1_0::SensorInfo> &dynamicSensorsAdded) override {
+ return SensorDevice::getInstance().onDynamicSensorsConnected(
+ convertToNewSensorInfos(dynamicSensorsAdded));
+ }
+
Return<void> onDynamicSensorsDisconnected(
const hidl_vec<int32_t> &dynamicSensorHandlesRemoved) override {
return SensorDevice::getInstance().onDynamicSensorsDisconnected(
@@ -126,7 +142,7 @@
Info model;
for (size_t i=0 ; i < count; i++) {
sensor_t sensor;
- convertToSensor(list[i], &sensor);
+ convertToSensor(convertToOldSensorInfo(list[i]), &sensor);
// Sanity check and clamp power if it is 0 (or close)
if (sensor.power < minPowerMa) {
ALOGI("Reported power %f not deemed sane, clamping to %f",
@@ -160,7 +176,11 @@
}
bool SensorDevice::connectHidlService() {
- HalConnectionStatus status = connectHidlServiceV2_0();
+ HalConnectionStatus status = connectHidlServiceV2_1();
+ if (status == HalConnectionStatus::DOES_NOT_EXIST) {
+ status = connectHidlServiceV2_0();
+ }
+
if (status == HalConnectionStatus::DOES_NOT_EXIST) {
status = connectHidlServiceV1_0();
}
@@ -180,7 +200,7 @@
break;
}
- mSensors = new SensorServiceUtil::SensorsWrapperV1_0(sensors);
+ mSensors = new ISensorsWrapperV1_0(sensors);
mRestartWaiter->reset();
// Poke ISensor service. If it has lingering connection from previous generation of
// system server, it will kill itself. There is no intention to handle the poll result,
@@ -208,40 +228,55 @@
if (sensors == nullptr) {
connectionStatus = HalConnectionStatus::DOES_NOT_EXIST;
} else {
- mSensors = new SensorServiceUtil::SensorsWrapperV2_0(sensors);
+ mSensors = new ISensorsWrapperV2_0(sensors);
+ connectionStatus = initializeHidlServiceV2_X();
+ }
- mEventQueue = std::make_unique<EventMessageQueue>(
- SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT,
- true /* configureEventFlagWord */);
+ return connectionStatus;
+}
- mWakeLockQueue = std::make_unique<WakeLockQueue>(
- SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT,
- true /* configureEventFlagWord */);
+SensorDevice::HalConnectionStatus SensorDevice::connectHidlServiceV2_1() {
+ HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
+ sp<V2_1::ISensors> sensors = V2_1::ISensors::getService();
- hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
- hardware::EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
+ if (sensors == nullptr) {
+ connectionStatus = HalConnectionStatus::DOES_NOT_EXIST;
+ } else {
+ mSensors = new ISensorsWrapperV2_1(sensors);
+ connectionStatus = initializeHidlServiceV2_X();
+ }
- hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
- hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(),
- &mWakeLockQueueFlag);
+ return connectionStatus;
+}
- CHECK(mSensors != nullptr && mEventQueue != nullptr &&
- mWakeLockQueue != nullptr && mEventQueueFlag != nullptr &&
- mWakeLockQueueFlag != nullptr);
+SensorDevice::HalConnectionStatus SensorDevice::initializeHidlServiceV2_X() {
+ HalConnectionStatus connectionStatus = HalConnectionStatus::UNKNOWN;
- status_t status = checkReturnAndGetStatus(mSensors->initialize(
- *mEventQueue->getDesc(),
- *mWakeLockQueue->getDesc(),
- new SensorsCallback()));
+ mWakeLockQueue = std::make_unique<WakeLockQueue>(
+ SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT,
+ true /* configureEventFlagWord */);
- if (status != NO_ERROR) {
- connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
- ALOGE("Failed to initialize Sensors HAL (%s)", strerror(-status));
- } else {
- connectionStatus = HalConnectionStatus::CONNECTED;
- mSensorsHalDeathReceiver = new SensorsHalDeathReceivier();
- sensors->linkToDeath(mSensorsHalDeathReceiver, 0 /* cookie */);
- }
+ hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
+ hardware::EventFlag::createEventFlag(mSensors->getEventQueue()->getEventFlagWord(), &mEventQueueFlag);
+
+ hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+ hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(),
+ &mWakeLockQueueFlag);
+
+ CHECK(mSensors != nullptr && mWakeLockQueue != nullptr &&
+ mEventQueueFlag != nullptr && mWakeLockQueueFlag != nullptr);
+
+ status_t status = checkReturnAndGetStatus(mSensors->initialize(
+ *mWakeLockQueue->getDesc(),
+ new SensorsCallback()));
+
+ if (status != NO_ERROR) {
+ connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
+ ALOGE("Failed to initialize Sensors HAL (%s)", strerror(-status));
+ } else {
+ connectionStatus = HalConnectionStatus::CONNECTED;
+ mSensorsHalDeathReceiver = new SensorsHalDeathReceivier();
+ mSensors->linkToDeath(mSensorsHalDeathReceiver, 0 /* cookie */);
}
return connectionStatus;
@@ -473,7 +508,8 @@
const auto &events,
const auto &dynamicSensorsAdded) {
if (result == Result::OK) {
- convertToSensorEvents(events, dynamicSensorsAdded, buffer);
+ convertToSensorEvents(convertToNewEvents(events),
+ convertToNewSensorInfos(dynamicSensorsAdded), buffer);
err = (ssize_t)events.size();
} else {
err = statusFromResult(result);
@@ -507,7 +543,7 @@
ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead) {
ssize_t eventsRead = 0;
- size_t availableEvents = mEventQueue->availableToRead();
+ size_t availableEvents = mSensors->getEventQueue()->availableToRead();
if (availableEvents == 0) {
uint32_t eventFlagState = 0;
@@ -518,7 +554,7 @@
// additional latency in delivering events to applications.
mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS) |
asBaseType(INTERNAL_WAKE), &eventFlagState);
- availableEvents = mEventQueue->availableToRead();
+ availableEvents = mSensors->getEventQueue()->availableToRead();
if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) {
ALOGD("Event FMQ internal wake, returning from poll with no events");
@@ -528,7 +564,7 @@
size_t eventsToRead = std::min({availableEvents, maxNumEventsToRead, mEventBuffer.size()});
if (eventsToRead > 0) {
- if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) {
+ if (mSensors->getEventQueue()->read(mEventBuffer.data(), eventsToRead)) {
// Notify the Sensors HAL that sensor events have been read. This is required to support
// the use of writeBlocking by the Sensors HAL.
mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::EVENTS_READ));
@@ -557,7 +593,7 @@
CHECK(it == mConnectedDynamicSensors.end());
sensor_t *sensor = new sensor_t();
- convertToSensor(info, sensor);
+ convertToSensor(convertToOldSensorInfo(info), sensor);
mConnectedDynamicSensors.insert(
std::make_pair(sensor->handle, sensor));
@@ -858,7 +894,7 @@
injected_sensor_event->data[5]);
Event ev;
- convertFromSensorEvent(*injected_sensor_event, &ev);
+ V2_1::implementation::convertFromSensorEvent(*injected_sensor_event, &ev);
return checkReturnAndGetStatus(mSensors->injectSensorData(ev));
}
@@ -1021,10 +1057,9 @@
void SensorDevice::convertToSensorEvent(
const Event &src, sensors_event_t *dst) {
- ::android::hardware::sensors::V1_0::implementation::convertToSensorEvent(
- src, dst);
+ V2_1::implementation::convertToSensorEvent(src, dst);
- if (src.sensorType == SensorType::DYNAMIC_SENSOR_META) {
+ if (src.sensorType == V2_1::SensorType::DYNAMIC_SENSOR_META) {
const DynamicSensorInfo &dyn = src.u.dynamic;
dst->dynamic_sensor_meta.connected = dyn.connected;
@@ -1052,7 +1087,7 @@
}
for (size_t i = 0; i < src.size(); ++i) {
- convertToSensorEvent(src[i], &dst[i]);
+ V2_1::implementation::convertToSensorEvent(src[i], &dst[i]);
}
}
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 33aa7d6..24d03c6 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -19,7 +19,7 @@
#include "SensorDeviceUtils.h"
#include "SensorServiceUtils.h"
-#include "SensorsWrapper.h"
+#include "ISensorsWrapper.h"
#include <fmq/MessageQueue.h>
#include <sensor/SensorEventQueue.h>
@@ -112,7 +112,7 @@
using Result = ::android::hardware::sensors::V1_0::Result;
hardware::Return<void> onDynamicSensorsConnected(
- const hardware::hidl_vec<hardware::sensors::V1_0::SensorInfo> &dynamicSensorsAdded);
+ const hardware::hidl_vec<hardware::sensors::V2_1::SensorInfo> &dynamicSensorsAdded);
hardware::Return<void> onDynamicSensorsDisconnected(
const hardware::hidl_vec<int32_t> &dynamicSensorHandlesRemoved);
@@ -128,7 +128,7 @@
private:
friend class Singleton<SensorDevice>;
- sp<SensorServiceUtil::ISensorsWrapper> mSensors;
+ sp<::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase> mSensors;
Vector<sensor_t> mSensorList;
std::unordered_map<int32_t, sensor_t*> mConnectedDynamicSensors;
@@ -205,6 +205,8 @@
};
HalConnectionStatus connectHidlServiceV1_0();
HalConnectionStatus connectHidlServiceV2_0();
+ HalConnectionStatus connectHidlServiceV2_1();
+ HalConnectionStatus initializeHidlServiceV2_X();
ssize_t pollHal(sensors_event_t* buffer, size_t count);
ssize_t pollFmq(sensors_event_t* buffer, size_t count);
@@ -226,8 +228,8 @@
bool isClientDisabled(void* ident);
bool isClientDisabledLocked(void* ident);
- using Event = hardware::sensors::V1_0::Event;
- using SensorInfo = hardware::sensors::V1_0::SensorInfo;
+ using Event = hardware::sensors::V2_1::Event;
+ using SensorInfo = hardware::sensors::V2_1::SensorInfo;
void convertToSensorEvent(const Event &src, sensors_event_t *dst);
@@ -238,9 +240,7 @@
bool mIsDirectReportSupported;
- typedef hardware::MessageQueue<Event, hardware::kSynchronizedReadWrite> EventMessageQueue;
typedef hardware::MessageQueue<uint32_t, hardware::kSynchronizedReadWrite> WakeLockQueue;
- std::unique_ptr<EventMessageQueue> mEventQueue;
std::unique_ptr<WakeLockQueue> mWakeLockQueue;
hardware::EventFlag* mEventQueueFlag;
diff --git a/services/sensorservice/SensorsWrapper.h b/services/sensorservice/SensorsWrapper.h
deleted file mode 100644
index d1a7234..0000000
--- a/services/sensorservice/SensorsWrapper.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SENSORS_WRAPPER_H
-#define ANDROID_SENSORS_WRAPPER_H
-
-#include "android/hardware/sensors/1.0/ISensors.h"
-#include "android/hardware/sensors/2.0/ISensors.h"
-#include "android/hardware/sensors/2.0/ISensorsCallback.h"
-
-#include <utils/LightRefBase.h>
-
-namespace android {
-namespace SensorServiceUtil {
-
-using ::android::hardware::MQDescriptorSync;
-using ::android::hardware::Return;
-using ::android::hardware::sensors::V1_0::Event;
-using ::android::hardware::sensors::V1_0::ISensors;
-using ::android::hardware::sensors::V1_0::OperationMode;
-using ::android::hardware::sensors::V1_0::RateLevel;
-using ::android::hardware::sensors::V1_0::Result;
-using ::android::hardware::sensors::V1_0::SharedMemInfo;
-using ::android::hardware::sensors::V2_0::ISensorsCallback;
-
-/*
- * The ISensorsWrapper interface includes all function from supported Sensors HAL versions. This
- * allows for the SensorDevice to use the ISensorsWrapper interface to interact with the Sensors
- * HAL regardless of the current version of the Sensors HAL that is loaded. Each concrete
- * instantiation of ISensorsWrapper must correspond to a specific Sensors HAL version. This design
- * is beneficial because only the functions that change between Sensors HAL versions must be newly
- * newly implemented, any previously implemented function that does not change may remain the same.
- *
- * Functions that exist across all versions of the Sensors HAL should be implemented as pure
- * virtual functions which forces the concrete instantiations to implement the functions.
- *
- * Functions that do not exist across all versions of the Sensors HAL should include a default
- * implementation that generates an error if called. The default implementation should never
- * be called and must be overridden by Sensors HAL versions that support the function.
- */
-class ISensorsWrapper : public VirtualLightRefBase {
-public:
- virtual bool supportsPolling() const = 0;
-
- virtual bool supportsMessageQueues() const = 0;
-
- virtual Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) = 0;
-
- virtual Return<Result> setOperationMode(OperationMode mode) = 0;
-
- virtual Return<Result> activate(int32_t sensorHandle, bool enabled) = 0;
-
- virtual Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
- int64_t maxReportLatencyNs) = 0;
-
- virtual Return<Result> flush(int32_t sensorHandle) = 0;
-
- virtual Return<Result> injectSensorData(const Event& event) = 0;
-
- virtual Return<void> registerDirectChannel(const SharedMemInfo& mem,
- ISensors::registerDirectChannel_cb _hidl_cb) = 0;
-
- virtual Return<Result> unregisterDirectChannel(int32_t channelHandle) = 0;
-
- virtual Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle,
- RateLevel rate,
- ISensors::configDirectReport_cb _hidl_cb) = 0;
-
- virtual Return<void> poll(int32_t maxCount, ISensors::poll_cb _hidl_cb) {
- (void)maxCount;
- (void)_hidl_cb;
- // TODO (b/111070257): Generate an assert-level error since this should never be called
- // directly
- return Return<void>();
- }
-
- virtual Return<Result> initialize(const MQDescriptorSync<Event>& eventQueueDesc,
- const MQDescriptorSync<uint32_t>& wakeLockDesc,
- const ::android::sp<ISensorsCallback>& callback) {
- (void)eventQueueDesc;
- (void)wakeLockDesc;
- (void)callback;
- // TODO (b/111070257): Generate an assert-level error since this should never be called
- // directly
- return Result::INVALID_OPERATION;
- }
-};
-
-template<typename T>
-class SensorsWrapperBase : public ISensorsWrapper {
-public:
- SensorsWrapperBase(sp<T> sensors) :
- mSensors(sensors) { };
-
- Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) override {
- return mSensors->getSensorsList(_hidl_cb);
- }
-
- Return<Result> setOperationMode(OperationMode mode) override {
- return mSensors->setOperationMode(mode);
- }
-
- Return<Result> activate(int32_t sensorHandle, bool enabled) override {
- return mSensors->activate(sensorHandle, enabled);
- }
-
- Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
- int64_t maxReportLatencyNs) override {
- return mSensors->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
- }
-
- Return<Result> flush(int32_t sensorHandle) override {
- return mSensors->flush(sensorHandle);
- }
-
- Return<Result> injectSensorData(const Event& event) override {
- return mSensors->injectSensorData(event);
- }
-
- Return<void> registerDirectChannel(const SharedMemInfo& mem,
- ISensors::registerDirectChannel_cb _hidl_cb) override {
- return mSensors->registerDirectChannel(mem, _hidl_cb);
- }
-
- Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
- return mSensors->unregisterDirectChannel(channelHandle);
- }
-
- Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle,
- RateLevel rate,
- ISensors::configDirectReport_cb _hidl_cb) override {
- return mSensors->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
- }
-
-protected:
- sp<T> mSensors;
-};
-
-class SensorsWrapperV1_0 : public SensorsWrapperBase<hardware::sensors::V1_0::ISensors> {
-public:
- SensorsWrapperV1_0(sp<hardware::sensors::V1_0::ISensors> sensors) :
- SensorsWrapperBase(sensors) { };
-
- bool supportsPolling() const override {
- return true;
- }
-
- bool supportsMessageQueues() const override {
- return false;
- }
-
- Return<void> poll(int32_t maxCount,
- hardware::sensors::V1_0::ISensors::poll_cb _hidl_cb) override {
- return mSensors->poll(maxCount, _hidl_cb);
- }
-};
-
-class SensorsWrapperV2_0 : public SensorsWrapperBase<hardware::sensors::V2_0::ISensors> {
-public:
- SensorsWrapperV2_0(sp<hardware::sensors::V2_0::ISensors> sensors)
- : SensorsWrapperBase(sensors) { };
-
- bool supportsPolling() const override {
- return false;
- }
-
- bool supportsMessageQueues() const override {
- return true;
- }
-
- Return<Result> initialize(const MQDescriptorSync<Event>& eventQueueDesc,
- const MQDescriptorSync<uint32_t>& wakeLockDesc,
- const ::android::sp<ISensorsCallback>& callback) override {
- return mSensors->initialize(eventQueueDesc, wakeLockDesc, callback);
- }
-};
-
-}; // namespace SensorServiceUtil
-}; // namespace android
-
-#endif // ANDROID_SENSORS_WRAPPER_H
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e65064b..f5a99ca 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -124,18 +124,6 @@
return isDue || !isPlausible;
}
-bool BufferQueueLayer::setFrameRate(FrameRate frameRate) {
- float oldFrameRate = 0.f;
- status_t result = mConsumer->getFrameRate(&oldFrameRate);
- bool frameRateChanged = result < 0 || frameRate.rate != oldFrameRate;
- mConsumer->setFrameRate(frameRate.rate);
- return frameRateChanged;
-}
-
-Layer::FrameRate BufferQueueLayer::getFrameRate() const {
- return FrameRate(mLatchedFrameRate, Layer::FrameRateCompatibility::Default);
-}
-
// -----------------------------------------------------------------------
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
@@ -578,7 +566,6 @@
mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse();
float latchedFrameRate;
mConsumer->getFrameRate(&latchedFrameRate);
- mLatchedFrameRate = latchedFrameRate;
}
sp<Layer> BufferQueueLayer::createClone() {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 626af4b..5f7587c 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -56,9 +56,6 @@
bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
- bool setFrameRate(FrameRate frameRate) override;
- FrameRate getFrameRate() const override;
-
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
@@ -155,8 +152,6 @@
std::atomic<bool> mSidebandStreamChanged{false};
sp<ContentsChangedListener> mContentsChangedListener;
-
- std::atomic<float> mLatchedFrameRate = 0.f;
};
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index 277081f..9aaef65 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -68,6 +68,36 @@
return letter < 'A' || letter > 'Z' ? '\0' : letter;
}
+DeviceProductInfo buildDeviceProductInfo(const Edid& edid) {
+ DeviceProductInfo info;
+ std::copy(edid.displayName.begin(), edid.displayName.end(), info.name.begin());
+ info.name[edid.displayName.size()] = '\0';
+
+ const auto productId = std::to_string(edid.productId);
+ std::copy(productId.begin(), productId.end(), info.productId.begin());
+ info.productId[productId.size()] = '\0';
+ info.manufacturerPnpId = edid.pnpId;
+
+ constexpr uint8_t kModelYearFlag = 0xff;
+ constexpr uint32_t kYearOffset = 1990;
+
+ const auto year = edid.manufactureOrModelYear + kYearOffset;
+ if (edid.manufactureWeek == kModelYearFlag) {
+ info.manufactureOrModelDate = DeviceProductInfo::ModelYear{.year = year};
+ } else if (edid.manufactureWeek == 0) {
+ DeviceProductInfo::ManufactureYear date;
+ date.year = year;
+ info.manufactureOrModelDate = date;
+ } else {
+ DeviceProductInfo::ManufactureWeekAndYear date;
+ date.year = year;
+ date.week = edid.manufactureWeek;
+ info.manufactureOrModelDate = date;
+ }
+
+ return info;
+}
+
} // namespace
uint16_t DisplayId::manufacturerId() const {
@@ -112,6 +142,31 @@
return {};
}
+ constexpr size_t kProductIdOffset = 10;
+ if (edid.size() < kProductIdOffset + sizeof(uint16_t)) {
+ ALOGE("Invalid EDID: product ID is truncated.");
+ return {};
+ }
+ const uint16_t productId = edid[kProductIdOffset] | (edid[kProductIdOffset + 1] << 8);
+
+ constexpr size_t kManufactureWeekOffset = 16;
+ if (edid.size() < kManufactureWeekOffset + sizeof(uint8_t)) {
+ ALOGE("Invalid EDID: manufacture week is truncated.");
+ return {};
+ }
+ const uint8_t manufactureWeek = edid[kManufactureWeekOffset];
+ ALOGW_IF(0x37 <= manufactureWeek && manufactureWeek <= 0xfe,
+ "Invalid EDID: week of manufacture cannot be in the range [0x37, 0xfe].");
+
+ constexpr size_t kManufactureYearOffset = 17;
+ if (edid.size() < kManufactureYearOffset + sizeof(uint8_t)) {
+ ALOGE("Invalid EDID: manufacture year is truncated.");
+ return {};
+ }
+ const uint8_t manufactureOrModelYear = edid[kManufactureYearOffset];
+ ALOGW_IF(manufactureOrModelYear <= 0xf,
+ "Invalid EDID: model year or manufacture year cannot be in the range [0x0, 0xf].");
+
constexpr size_t kDescriptorOffset = 54;
if (edid.size() < kDescriptorOffset) {
ALOGE("Invalid EDID: descriptors are missing.");
@@ -127,6 +182,7 @@
constexpr size_t kDescriptorCount = 4;
constexpr size_t kDescriptorLength = 18;
+ static_assert(kDescriptorLength - kEdidHeaderLength < DeviceProductInfo::TEXT_BUFFER_SIZE);
for (size_t i = 0; i < kDescriptorCount; i++) {
if (view.size() < kDescriptorLength) {
@@ -166,7 +222,12 @@
return {};
}
- return Edid{manufacturerId, *pnpId, displayName};
+ return Edid{.manufacturerId = manufacturerId,
+ .pnpId = *pnpId,
+ .displayName = displayName,
+ .productId = productId,
+ .manufactureWeek = manufactureWeek,
+ .manufactureOrModelYear = manufactureOrModelYear};
}
std::optional<PnpId> getPnpId(uint16_t manufacturerId) {
@@ -195,8 +256,9 @@
// Hash display name instead of using product code or serial number, since the latter have been
// observed to change on some displays with multiple inputs.
const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName));
- return DisplayIdentificationInfo{DisplayId::fromEdid(port, edid->manufacturerId, hash),
- std::string(edid->displayName)};
+ return DisplayIdentificationInfo{.id = DisplayId::fromEdid(port, edid->manufacturerId, hash),
+ .name = std::string(edid->displayName),
+ .deviceProductInfo = buildDeviceProductInfo(*edid)};
}
DisplayId getFallbackDisplayId(uint8_t port) {
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index 22b268a..0a18ba1 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -23,6 +23,7 @@
#include <string_view>
#include <vector>
+#include <ui/DeviceProductInfo.h>
#include <ui/PhysicalDisplayId.h>
namespace android {
@@ -53,15 +54,16 @@
struct DisplayIdentificationInfo {
DisplayId id;
std::string name;
+ std::optional<DeviceProductInfo> deviceProductInfo;
};
-// NUL-terminated plug and play ID.
-using PnpId = std::array<char, 4>;
-
struct Edid {
uint16_t manufacturerId;
+ uint16_t productId;
PnpId pnpId;
std::string_view displayName;
+ uint8_t manufactureOrModelYear;
+ uint8_t manufactureWeek;
};
bool isEdid(const DisplayIdentificationData&);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 784fa74..1c1e113 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -208,7 +208,9 @@
std::optional<DisplayIdentificationInfo> info;
if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) {
- info = DisplayIdentificationInfo{*displayId, std::string()};
+ info = DisplayIdentificationInfo{.id = *displayId,
+ .name = std::string(),
+ .deviceProductInfo = std::nullopt};
} else {
if (connection == HWC2::Connection::Disconnected) {
ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId);
@@ -951,9 +953,11 @@
if (info) return info;
- return DisplayIdentificationInfo{getFallbackDisplayId(port),
- hwcDisplayId == mInternalHwcDisplayId ? "Internal display"
- : "External display"};
+ return DisplayIdentificationInfo{.id = getFallbackDisplayId(port),
+ .name = hwcDisplayId == mInternalHwcDisplayId
+ ? "Internal display"
+ : "External display",
+ .deviceProductInfo = std::nullopt};
}
void HWComposer::loadCapabilities() {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index da26a37..d7647d7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -26,6 +26,7 @@
#include "Layer.h"
#include <android-base/stringprintf.h>
+#include <android/native_window.h>
#include <binder/IPCThreadState.h>
#include <compositionengine/Display.h>
#include <compositionengine/LayerFECompositionState.h>
@@ -2446,6 +2447,18 @@
layer->mDrawingParent = this;
}
+Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t compatibility) {
+ switch (compatibility) {
+ case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT:
+ return FrameRateCompatibility::Default;
+ case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE:
+ return FrameRateCompatibility::ExactOrMultiple;
+ default:
+ LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility);
+ return FrameRateCompatibility::Default;
+ }
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 37ae340..5d2144a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -161,6 +161,10 @@
}
bool operator!=(const FrameRate& other) const { return !(*this == other); }
+
+ // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a
+ // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid.
+ static FrameRateCompatibility convertCompatibility(int8_t compatibility);
};
struct State {
@@ -795,7 +799,7 @@
*/
Rect getCroppedBufferSize(const Layer::State& s) const;
- virtual bool setFrameRate(FrameRate frameRate);
+ bool setFrameRate(FrameRate frameRate);
virtual FrameRate getFrameRate() const;
protected:
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index b313777..a8e6756 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -97,6 +97,7 @@
}
LayerHistory::Summary LayerHistory::summarize(nsecs_t now) {
+ ATRACE_CALL();
std::lock_guard lock(mLock);
partitionLayers(now);
@@ -179,4 +180,3 @@
mActiveLayersEnd = 0;
}
} // namespace android::scheduler::impl
-
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index 345b8f9..b755798 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -61,21 +61,35 @@
}
bool LayerInfoV2::isFrequent(nsecs_t now) const {
+ // Find the first valid frame time
+ auto it = mFrameTimes.begin();
+ for (; it != mFrameTimes.end(); ++it) {
+ if (isFrameTimeValid(*it)) {
+ break;
+ }
+ }
+
// If we know nothing about this layer we consider it as frequent as it might be the start
// of an animation.
- if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) {
+ if (std::distance(it, mFrameTimes.end()) < FREQUENT_LAYER_WINDOW_SIZE) {
return true;
}
- // Layer is frequent if the earliest value in the window of most recent present times is
- // within threshold.
- const auto it = mFrameTimes.end() - FREQUENT_LAYER_WINDOW_SIZE;
- if (!isFrameTimeValid(*it)) {
- return true;
+ // Find the first active frame
+ for (; it != mFrameTimes.end(); ++it) {
+ if (it->queueTime >= getActiveLayerThreshold(now)) {
+ break;
+ }
}
- const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count();
- return it->queueTime >= threshold;
+ const auto numFrames = std::distance(it, mFrameTimes.end()) - 1;
+ if (numFrames <= 0) {
+ return false;
+ }
+
+ // Layer is considered frequent if the average frame rate is higher than the threshold
+ const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
+ return (1e9f * numFrames) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
}
bool LayerInfoV2::hasEnoughDataForHeuristic() const {
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index 90f6310..25fb95a 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -47,7 +47,9 @@
// is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
// favor of a low refresh rate.
static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3;
- static constexpr std::chrono::nanoseconds MAX_FREQUENT_LAYER_PERIOD_NS = 250ms;
+ static constexpr float MIN_FPS_FOR_FREQUENT_LAYER = 10.0f;
+ static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS =
+ std::chrono::nanoseconds(static_cast<nsecs_t>(1e9f / MIN_FPS_FOR_FREQUENT_LAYER)) + 1ms;
friend class LayerHistoryTestV2;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index d1de737..b876ccd 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -23,8 +23,6 @@
#include <chrono>
#include <cmath>
-using namespace std::chrono_literals;
-
namespace android::scheduler {
using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
@@ -84,14 +82,31 @@
return *bestSoFar;
}
+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;
+ }
+
+ return {displayFramesQuot, displayFramesRem};
+}
+
const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
- const std::vector<LayerRequirement>& layers) const {
- constexpr nsecs_t MARGIN = std::chrono::nanoseconds(800us).count();
+ const std::vector<LayerRequirement>& layers, bool touchActive) const {
ATRACE_CALL();
ALOGV("getRefreshRateForContent %zu layers", layers.size());
std::lock_guard lock(mLock);
+ // For now if the touch is active return the peak refresh rate
+ // This should be optimized to consider other layers as well.
+ if (touchActive) {
+ return *mAvailableRefreshRates.back();
+ }
+
int noVoteLayers = 0;
int minVoteLayers = 0;
int maxVoteLayers = 0;
@@ -115,11 +130,6 @@
return *mAvailableRefreshRates.front();
}
- // If we have some Max layers and no Explicit we should return Max
- if (maxVoteLayers > 0 && explicitDefaultVoteLayers + explicitExactOrMultipleVoteLayers == 0) {
- return *mAvailableRefreshRates.back();
- }
-
// Find the best refresh rate based on score
std::vector<std::pair<const RefreshRate*, float>> scores;
scores.reserve(mAvailableRefreshRates.size());
@@ -130,67 +140,85 @@
for (const auto& layer : layers) {
ALOGV("Calculating score for %s (type: %d)", layer.name.c_str(), layer.vote);
- if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min ||
- layer.vote == LayerVoteType::Max) {
+ if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) {
continue;
}
- // Adjust the weight in case we have explicit layers. The priority is:
- // - ExplicitExactOrMultiple
- // - ExplicitDefault
- // - Heuristic
auto weight = layer.weight;
- if (explicitExactOrMultipleVoteLayers + explicitDefaultVoteLayers > 0) {
- if (layer.vote == LayerVoteType::Heuristic) {
- weight /= 2.f;
- }
- }
- if (explicitExactOrMultipleVoteLayers > 0) {
- if (layer.vote == LayerVoteType::Heuristic ||
- layer.vote == LayerVoteType::ExplicitDefault) {
- weight /= 2.f;
+ for (auto i = 0u; i < scores.size(); i++) {
+ // 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 / scores.back().first->fps;
+ // use ratio^2 to get a lower score the more we get further from peak
+ const auto layerScore = ratio * ratio;
+ ALOGV("%s (Max, weight %.2f) gives %s score of %.2f", layer.name.c_str(), weight,
+ scores[i].first->name.c_str(), layerScore);
+ scores[i].second += weight * layerScore;
+ continue;
}
- }
- for (auto& [refreshRate, overallScore] : scores) {
- const auto displayPeriod = refreshRate->vsyncPeriod;
+ const auto displayPeriod = scores[i].first->vsyncPeriod;
const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate);
+ if (layer.vote == LayerVoteType::ExplicitDefault) {
+ const auto layerScore = [&]() {
+ const auto [displayFramesQuot, displayFramesRem] =
+ getDisplayFrames(layerPeriod, displayPeriod);
+ if (displayFramesQuot == 0) {
+ // Layer desired refresh rate is higher the display rate.
+ return static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod);
+ }
- // Calculate how many display vsyncs we need to present a single frame for this layer
- auto [displayFramesQuot, displayFramesRem] = std::div(layerPeriod, displayPeriod);
- if (displayFramesRem <= MARGIN ||
- std::abs(displayFramesRem - displayPeriod) <= MARGIN) {
- displayFramesQuot++;
- displayFramesRem = 0;
+ return 1.0f -
+ (static_cast<float>(displayFramesRem) /
+ static_cast<float>(layerPeriod));
+ }();
+
+ ALOGV("%s (ExplicitDefault, weight %.2f) %.2fHz gives %s score of %.2f",
+ layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(),
+ layerScore);
+ scores[i].second += weight * layerScore;
+ continue;
}
- float layerScore;
- 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.
- layerScore = weight * 1.0f;
- } else if (displayFramesQuot == 0) {
- // Layer desired refresh rate is higher the display rate.
- layerScore = weight *
- (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
- (1.0f / (MAX_FRAMES_TO_FIT + 1));
- } else {
- // 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 && iter < MAX_FRAMES_TO_FIT) {
- diff = diff - (displayPeriod - diff);
- iter++;
- }
+ 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;
+ }
- layerScore = weight * (1.0f / iter);
+ 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;
+ }();
+ ALOGV("%s (ExplicitExactOrMultiple, weight %.2f) %.2fHz gives %s score of %.2f",
+ layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(),
+ layerScore);
+ scores[i].second += weight * layerScore;
+ continue;
}
-
- ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), weight,
- 1e9f / layerPeriod, refreshRate->name.c_str(), layerScore);
- overallScore += layerScore;
}
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 1132a8c..0b5c73c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -28,6 +28,7 @@
#include "Scheduler/StrongTyping.h"
namespace android::scheduler {
+using namespace std::chrono_literals;
enum class RefreshRateConfigEvent : unsigned { None = 0b0, Changed = 0b1 };
@@ -43,6 +44,10 @@
*/
class RefreshRateConfigs {
public:
+ // Margin used when matching refresh rates to the content desired ones.
+ static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION =
+ std::chrono::nanoseconds(800us).count();
+
struct RefreshRate {
// The tolerance within which we consider FPS approximately equals.
static constexpr float FPS_EPSILON = 0.001f;
@@ -123,13 +128,15 @@
bool operator!=(const LayerRequirement& other) const { return !(*this == other); }
};
- // Returns all available refresh rates according to the current policy.
+ // Returns the refresh rate that fits best to the given layers.
const RefreshRate& getRefreshRateForContent(const std::vector<LayerRequirement>& layers) const
EXCLUDES(mLock);
- // Returns all available refresh rates according to the current policy.
- const RefreshRate& getRefreshRateForContentV2(const std::vector<LayerRequirement>& layers) const
- EXCLUDES(mLock);
+ // Returns the refresh rate that fits best to the given layers. This function also gets a
+ // boolean flag that indicates whether user touched the screen recently to be factored in when
+ // choosing the refresh rate.
+ const RefreshRate& getRefreshRateForContentV2(const std::vector<LayerRequirement>& layers,
+ bool touchActive) const EXCLUDES(mLock);
// Returns all the refresh rates supported by the device. This won't change at runtime.
const AllRefreshRatesMapType& getAllRefreshRates() const EXCLUDES(mLock);
@@ -188,6 +195,10 @@
template <typename Iter>
const RefreshRate* getBestRefreshRate(Iter begin, Iter end) const;
+ // Returns number of display frames and remainder when dividing the layer refresh period by
+ // display refresh period.
+ std::pair<nsecs_t, nsecs_t> getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const;
+
// The list of refresh rates, indexed by display config ID. This must not change after this
// object is initialized.
AllRefreshRatesMapType mRefreshRates;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 71ac90e..3a44332 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -439,7 +439,7 @@
return;
}
mFeatures.contentRequirements = summary;
- mFeatures.contentDetection =
+ mFeatures.contentDetectionV1 =
!summary.empty() ? ContentDetectionState::On : ContentDetectionState::Off;
newConfigId = calculateRefreshRateConfigIndexType();
@@ -466,7 +466,7 @@
// NOTE: Instead of checking all the layers, we should be checking the layer
// that is currently on top. b/142507166 will give us this capability.
std::lock_guard<std::mutex> lock(mFeatureStateLock);
- if (mLayerHistory && !layerHistoryHasClientSpecifiedFrameRate()) {
+ if (mLayerHistory) {
mLayerHistory->clear();
mTouchTimer->reset();
@@ -556,7 +556,7 @@
return;
}
mFeatures.configId = newConfigId;
- if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) {
+ if (eventOnContentDetection && !mFeatures.contentRequirements.empty()) {
event = ConfigEvent::Changed;
}
}
@@ -564,33 +564,10 @@
mSchedulerCallback.changeRefreshRate(newRefreshRate, event);
}
-bool Scheduler::layerHistoryHasClientSpecifiedFrameRate() {
- // Traverse all the layers to see if any of them requested frame rate.
- for (const auto& layer : mFeatures.contentRequirements) {
- if (layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitDefault ||
- layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitExactOrMultiple) {
- return true;
- }
- }
-
- return false;
-}
-
HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() {
- // This block of the code checks whether any layers used the SetFrameRate API. If they have,
- // their request should be honored depending on other active layers.
- if (layerHistoryHasClientSpecifiedFrameRate()) {
- if (!mUseContentDetectionV2) {
- return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements)
- .configId;
- } else {
- return mRefreshRateConfigs.getRefreshRateForContentV2(mFeatures.contentRequirements)
- .configId;
- }
- }
+ ATRACE_CALL();
- // If the layer history doesn't have the frame rate specified, check for other features and
- // honor them. NOTE: If we remove the kernel idle timer, and use our internal idle timer, this
+ // NOTE: If we remove the kernel idle timer, and use our internal idle timer, this
// code will have to be refactored. If Display Power is not in normal operation we want to be in
// performance mode. When coming back to normal mode, a grace period is given with
// DisplayPowerTimer.
@@ -600,9 +577,11 @@
return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
}
- // As long as touch is active we want to be in performance mode.
- if (mTouchTimer && mFeatures.touch == TouchState::Active) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ if (!mUseContentDetectionV2) {
+ // As long as touch is active we want to be in performance mode.
+ if (mTouchTimer && mFeatures.touch == TouchState::Active) {
+ return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ }
}
// If timer has expired as it means there is no new content on the screen.
@@ -612,7 +591,7 @@
if (!mUseContentDetectionV2) {
// If content detection is off we choose performance as we don't know the content fps.
- if (mFeatures.contentDetection == ContentDetectionState::Off) {
+ if (mFeatures.contentDetectionV1 == ContentDetectionState::Off) {
// NOTE: V1 always calls this, but this is not a default behavior for V2.
return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
}
@@ -621,14 +600,10 @@
return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements).configId;
}
- // Content detection is on, find the appropriate refresh rate with minimal error
- if (mFeatures.contentDetection == ContentDetectionState::On) {
- return mRefreshRateConfigs.getRefreshRateForContentV2(mFeatures.contentRequirements)
- .configId;
- }
-
- // There are no signals for refresh rate, just leave it as is.
- return mRefreshRateConfigs.getCurrentRefreshRateByPolicy().configId;
+ return mRefreshRateConfigs
+ .getRefreshRateForContentV2(mFeatures.contentRequirements,
+ mTouchTimer && mFeatures.touch == TouchState::Active)
+ .configId;
}
std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 81051be..46d1a5e 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -185,8 +185,6 @@
// for the suggested refresh rate.
HwcConfigIndexType calculateRefreshRateConfigIndexType() REQUIRES(mFeatureStateLock);
- bool layerHistoryHasClientSpecifiedFrameRate() REQUIRES(mFeatureStateLock);
-
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
struct Connection {
sp<EventThreadConnection> connection;
@@ -229,7 +227,7 @@
std::mutex mFeatureStateLock;
struct {
- ContentDetectionState contentDetection = ContentDetectionState::Off;
+ ContentDetectionState contentDetectionV1 = ContentDetectionState::Off;
TimerState idleTimer = TimerState::Reset;
TouchState touch = TouchState::Inactive;
TimerState displayPowerTimer = TimerState::Expired;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a98ff4f..fbebea0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -34,6 +34,8 @@
#include <optional>
#include <unordered_map>
+#include <android/native_window.h>
+
#include <cutils/properties.h>
#include <log/log.h>
@@ -58,6 +60,7 @@
#include <gui/IProducerListener.h>
#include <gui/LayerDebugInfo.h>
#include <gui/LayerMetadata.h>
+#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <input/IInputFlinger.h>
#include <renderengine/RenderEngine.h>
@@ -798,6 +801,7 @@
}
info->secure = display->isSecure();
+ info->deviceProductInfo = getDeviceProductInfoLocked(*display);
return NO_ERROR;
}
@@ -1272,6 +1276,30 @@
return NO_ERROR;
}
+std::optional<DeviceProductInfo> SurfaceFlinger::getDeviceProductInfoLocked(
+ const DisplayDevice& display) const {
+ // TODO(b/149075047): Populate DeviceProductInfo on hotplug and store it in DisplayDevice to
+ // avoid repetitive HAL IPC and EDID parsing.
+ const auto displayId = display.getId();
+ LOG_FATAL_IF(!displayId);
+
+ const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
+ LOG_FATAL_IF(!hwcDisplayId);
+
+ uint8_t port;
+ DisplayIdentificationData data;
+ if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
+ ALOGV("%s: No identification data.", __FUNCTION__);
+ return {};
+ }
+
+ const auto info = parseDisplayIdentificationData(port, data);
+ if (!info) {
+ return {};
+ }
+ return info->deviceProductInfo;
+}
+
status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken,
ui::PixelFormat* outFormat,
ui::Dataspace* outDataspace,
@@ -3574,9 +3602,13 @@
}
}
if (what & layer_state_t::eFrameRateChanged) {
- if (layer->setFrameRate(
- Layer::FrameRate(s.frameRate, Layer::FrameRateCompatibility::Default)))
+ if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility,
+ "SurfaceFlinger::setClientStateLocked") &&
+ layer->setFrameRate(Layer::FrameRate(s.frameRate,
+ Layer::FrameRate::convertCompatibility(
+ s.frameRateCompatibility)))) {
flags |= eTraversalNeeded;
+ }
}
// This has to happen after we reparent children because when we reparent to null we remove
// child layers from current state and remove its relative z. If the children are reparented in
@@ -4674,6 +4706,9 @@
case GET_COMPOSITION_PREFERENCE:
case GET_PROTECTED_CONTENT_SUPPORT:
case IS_WIDE_COLOR_DISPLAY:
+ // setFrameRate() is deliberately available for apps to call without any
+ // special permissions.
+ case SET_FRAME_RATE:
case GET_DISPLAY_BRIGHTNESS_SUPPORT:
case SET_DISPLAY_BRIGHTNESS: {
return OK;
@@ -5887,6 +5922,27 @@
return genericLayerMetadataKeyMap;
}
+status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
+ int8_t compatibility) {
+ if (!ValidateFrameRate(frameRate, compatibility, "SurfaceFlinger::setFrameRate")) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mStateLock);
+ if (authenticateSurfaceTextureLocked(surface)) {
+ sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
+ if (layer->setFrameRate(
+ Layer::FrameRate(frameRate,
+ Layer::FrameRate::convertCompatibility(compatibility)))) {
+ setTransactionFlags(eTraversalNeeded);
+ }
+ } else {
+ ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer");
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0144b4e..dcbb150 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -493,6 +493,8 @@
status_t notifyPowerHint(int32_t hintId) override;
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override;
+ status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
+ int8_t compatibility) override;
/* ------------------------------------------------------------------------
* DeathRecipient interface
*/
@@ -758,6 +760,8 @@
return nullptr;
}
+ std::optional<DeviceProductInfo> getDeviceProductInfoLocked(const DisplayDevice&) const;
+
// mark a region of a layer stack dirty. this updates the dirty
// region of all screens presenting this layer stack.
void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
diff --git a/services/surfaceflinger/tests/SetFrameRate_test.cpp b/services/surfaceflinger/tests/SetFrameRate_test.cpp
index fc65263..02ba9e2 100644
--- a/services/surfaceflinger/tests/SetFrameRate_test.cpp
+++ b/services/surfaceflinger/tests/SetFrameRate_test.cpp
@@ -58,17 +58,23 @@
TEST_F(SetFrameRateTest, BufferQueueLayerSetFrameRate) {
CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferQueue);
- native_window_set_frame_rate(mLayer->getSurface().get(), 100.f);
+ native_window_set_frame_rate(mLayer->getSurface().get(), 100.f,
+ ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
- Transaction().setFrameRate(mLayer, 200.f).apply();
+ Transaction()
+ .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT)
+ .apply();
ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
- native_window_set_frame_rate(mLayer->getSurface().get(), 300.f);
+ native_window_set_frame_rate(mLayer->getSurface().get(), 300.f,
+ ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
}
TEST_F(SetFrameRateTest, BufferStateLayerSetFrameRate) {
CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferState);
- Transaction().setFrameRate(mLayer, 400.f).apply();
+ Transaction()
+ .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT)
+ .apply();
ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::GREEN));
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index 55995d0..a023367 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -61,6 +61,64 @@
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6";
+const unsigned char kPanasonicTvEdid[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x34\xa9\x96\xa2\x01\x01\x01"
+ "\x01\x00\x1d\x01\x03\x80\x80\x48\x78\x0a\xda\xff\xa3\x58\x4a"
+ "\xa2\x29\x17\x49\x4b\x20\x08\x00\x31\x40\x61\x40\x01\x01\x01"
+ "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x08\xe8\x00\x30\xf2\x70"
+ "\x5a\x80\xb0\x58\x8a\x00\xba\x88\x21\x00\x00\x1e\x02\x3a\x80"
+ "\x18\x71\x38\x2d\x40\x58\x2c\x45\x00\xba\x88\x21\x00\x00\x1e"
+ "\x00\x00\x00\xfc\x00\x50\x61\x6e\x61\x73\x6f\x6e\x69\x63\x2d"
+ "\x54\x56\x0a\x00\x00\x00\xfd\x00\x17\x3d\x0f\x88\x3c\x00\x0a"
+ "\x20\x20\x20\x20\x20\x20\x01\x1d\x02\x03\x6b\xf0\x57\x61\x60"
+ "\x10\x1f\x66\x65\x05\x14\x20\x21\x22\x04\x13\x03\x12\x07\x16"
+ "\x5d\x5e\x5f\x62\x63\x64\x2c\x0d\x07\x01\x15\x07\x50\x57\x07"
+ "\x01\x67\x04\x03\x83\x0f\x00\x00\x6e\x03\x0c\x00\x20\x00\x38"
+ "\x3c\x2f\x08\x80\x01\x02\x03\x04\x67\xd8\x5d\xc4\x01\x78\x80"
+ "\x03\xe2\x00\x4b\xe3\x05\xff\x01\xe2\x0f\x33\xe3\x06\x0f\x01"
+ "\xe5\x01\x8b\x84\x90\x01\xeb\x01\x46\xd0\x00\x44\x03\x70\x80"
+ "\x5e\x75\x94\xe6\x11\x46\xd0\x00\x70\x00\x66\x21\x56\xaa\x51"
+ "\x00\x1e\x30\x46\x8f\x33\x00\xba\x88\x21\x00\x00\x1e\x00\x00"
+ "\xc8";
+
+const unsigned char kHisenseTvEdid[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x20\xa3\x00\x00\x00\x00\x00"
+ "\x00\x12\x1d\x01\x03\x80\x00\x00\x78\x0a\xd7\xa5\xa2\x59\x4a"
+ "\x96\x24\x14\x50\x54\xa3\x08\x00\xd1\xc0\xb3\x00\x81\x00\x81"
+ "\x80\x81\x40\x81\xc0\x01\x01\x01\x01\x02\x3a\x80\x18\x71\x38"
+ "\x2d\x40\x58\x2c\x45\x00\x3f\x43\x21\x00\x00\x1a\x02\x3a\x80"
+ "\x18\x71\x38\x2d\x40\x58\x2c\x45\x00\x3f\x43\x21\x00\x00\x1a"
+ "\x00\x00\x00\xfd\x00\x1e\x4c\x1e\x5a\x1e\x00\x0a\x20\x20\x20"
+ "\x20\x20\x20\x00\x00\x00\xfc\x00\x48\x69\x73\x65\x6e\x73\x65"
+ "\x0a\x20\x20\x20\x20\x20\x01\x47\x02\x03\x2d\x71\x50\x90\x05"
+ "\x04\x03\x07\x02\x06\x01\x1f\x14\x13\x12\x16\x11\x15\x20\x2c"
+ "\x09\x07\x03\x15\x07\x50\x57\x07\x00\x39\x07\xbb\x66\x03\x0c"
+ "\x00\x20\x00\x00\x83\x01\x00\x00\x01\x1d\x00\x72\x51\xd0\x1e"
+ "\x20\x6e\x28\x55\x00\xc4\x8e\x21\x00\x00\x1e\x01\x1d\x80\x18"
+ "\x71\x1c\x16\x20\x58\x2c\x25\x00\xc4\x8e\x21\x00\x00\x9e\x8c"
+ "\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\x13\x8e\x21\x00"
+ "\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x07";
+
+const unsigned char kCtlDisplayEdid[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x0e\x8c\x9d\x24\x00\x00\x00\x00"
+ "\xff\x17\x01\x04\xa5\x34\x1d\x78\x3a\xa7\x25\xa4\x57\x51\xa0\x26"
+ "\x10\x50\x54\xbf\xef\x80\xb3\x00\xa9\x40\x95\x00\x81\x40\x81\x80"
+ "\x95\x0f\x71\x4f\x90\x40\x02\x3a\x80\x18\x71\x38\x2d\x40\x58\x2c"
+ "\x45\x00\x09\x25\x21\x00\x00\x1e\x66\x21\x50\xb0\x51\x00\x1b\x30"
+ "\x40\x70\x36\x00\x09\x25\x21\x00\x00\x1e\x00\x00\x00\xfd\x00\x31"
+ "\x4c\x1e\x52\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc"
+ "\x00\x4c\x50\x32\x33\x36\x31\x0a\x20\x20\x20\x20\x20\x20\x01\x3e"
+ "\x02\x03\x22\xf2\x4f\x90\x9f\x05\x14\x04\x13\x03\x02\x12\x11\x07"
+ "\x06\x16\x15\x01\x23\x09\x07\x07\x83\x01\x00\x00\x65\xb9\x14\x00"
+ "\x04\x00\x02\x3a\x80\x18\x71\x38\x2d\x40\x58\x2c\x45\x00\x09\x25"
+ "\x21\x00\x00\x1e\x02\x3a\x80\xd0\x72\x38\x2d\x40\x10\x2c\x45\x80"
+ "\x09\x25\x21\x00\x00\x1e\x01\x1d\x00\x72\x51\xd0\x1e\x20\x6e\x28"
+ "\x55\x00\x09\x25\x21\x00\x00\x1e\x8c\x0a\xd0\x8a\x20\xe0\x2d\x10"
+ "\x10\x3e\x96\x00\x09\x25\x21\x00\x00\x18\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4";
+
template <size_t N>
DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&bytes)[N]) {
return DisplayIdentificationData(bytes, bytes + N - 1);
@@ -83,12 +141,30 @@
return data;
}
+const DisplayIdentificationData& getPanasonicTvEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kPanasonicTvEdid);
+ return data;
+}
+
+const DisplayIdentificationData& getHisenseTvEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kHisenseTvEdid);
+ return data;
+}
+
+const DisplayIdentificationData& getCtlDisplayEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kCtlDisplayEdid);
+ return data;
+}
+
TEST(DisplayIdentificationTest, isEdid) {
EXPECT_FALSE(isEdid({}));
EXPECT_TRUE(isEdid(getInternalEdid()));
EXPECT_TRUE(isEdid(getExternalEdid()));
EXPECT_TRUE(isEdid(getExternalEedid()));
+ EXPECT_TRUE(isEdid(getPanasonicTvEdid()));
+ EXPECT_TRUE(isEdid(getHisenseTvEdid()));
+ EXPECT_TRUE(isEdid(getCtlDisplayEdid()));
}
TEST(DisplayIdentificationTest, parseEdid) {
@@ -98,18 +174,54 @@
EXPECT_STREQ("SEC", edid->pnpId.data());
// ASCII text should be used as fallback if display name and serial number are missing.
EXPECT_EQ("121AT11-801", edid->displayName);
+ EXPECT_EQ(12610, edid->productId);
+ EXPECT_EQ(21, edid->manufactureOrModelYear);
+ EXPECT_EQ(0, edid->manufactureWeek);
edid = parseEdid(getExternalEdid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x22f0u, edid->manufacturerId);
EXPECT_STREQ("HWP", edid->pnpId.data());
EXPECT_EQ("HP ZR30w", edid->displayName);
+ EXPECT_EQ(10348, edid->productId);
+ EXPECT_EQ(22, edid->manufactureOrModelYear);
+ EXPECT_EQ(2, edid->manufactureWeek);
edid = parseEdid(getExternalEedid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x4c2du, edid->manufacturerId);
EXPECT_STREQ("SAM", edid->pnpId.data());
EXPECT_EQ("SAMSUNG", edid->displayName);
+ EXPECT_EQ(2302, edid->productId);
+ EXPECT_EQ(21, edid->manufactureOrModelYear);
+ EXPECT_EQ(41, edid->manufactureWeek);
+
+ edid = parseEdid(getPanasonicTvEdid());
+ ASSERT_TRUE(edid);
+ EXPECT_EQ(13481, edid->manufacturerId);
+ EXPECT_STREQ("MEI", edid->pnpId.data());
+ EXPECT_EQ("Panasonic-TV", edid->displayName);
+ EXPECT_EQ(41622, edid->productId);
+ EXPECT_EQ(29, edid->manufactureOrModelYear);
+ EXPECT_EQ(0, edid->manufactureWeek);
+
+ edid = parseEdid(getHisenseTvEdid());
+ ASSERT_TRUE(edid);
+ EXPECT_EQ(8355, edid->manufacturerId);
+ EXPECT_STREQ("HEC", edid->pnpId.data());
+ EXPECT_EQ("Hisense", edid->displayName);
+ EXPECT_EQ(0, edid->productId);
+ EXPECT_EQ(29, edid->manufactureOrModelYear);
+ EXPECT_EQ(18, edid->manufactureWeek);
+
+ edid = parseEdid(getCtlDisplayEdid());
+ ASSERT_TRUE(edid);
+ EXPECT_EQ(3724, edid->manufacturerId);
+ EXPECT_STREQ("CTL", edid->pnpId.data());
+ EXPECT_EQ("LP2361", edid->displayName);
+ EXPECT_EQ(9373, edid->productId);
+ EXPECT_EQ(23, edid->manufactureOrModelYear);
+ EXPECT_EQ(0xff, edid->manufactureWeek);
}
TEST(DisplayIdentificationTest, parseInvalidEdid) {
@@ -156,6 +268,86 @@
EXPECT_NE(secondaryInfo->id, tertiaryInfo->id);
}
+TEST(DisplayIdentificationTest, deviceProductInfo) {
+ using ManufactureYear = DeviceProductInfo::ManufactureYear;
+ using ManufactureWeekAndYear = DeviceProductInfo::ManufactureWeekAndYear;
+ using ModelYear = DeviceProductInfo::ModelYear;
+
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getInternalEdid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("121AT11-801", info.name.data());
+ EXPECT_STREQ("SEC", info.manufacturerPnpId.data());
+ EXPECT_STREQ("12610", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
+ EXPECT_EQ(2011, std::get<ManufactureYear>(info.manufactureOrModelDate).year);
+ }
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEdid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("HP ZR30w", info.name.data());
+ EXPECT_STREQ("HWP", info.manufacturerPnpId.data());
+ EXPECT_STREQ("10348", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
+ const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
+ EXPECT_EQ(2012, date.year);
+ EXPECT_EQ(2, date.week);
+ }
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEedid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("SAMSUNG", info.name.data());
+ EXPECT_STREQ("SAM", info.manufacturerPnpId.data());
+ EXPECT_STREQ("2302", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
+ const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
+ EXPECT_EQ(2011, date.year);
+ EXPECT_EQ(41, date.week);
+ }
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getPanasonicTvEdid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("Panasonic-TV", info.name.data());
+ EXPECT_STREQ("MEI", info.manufacturerPnpId.data());
+ EXPECT_STREQ("41622", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
+ const auto& date = std::get<ManufactureYear>(info.manufactureOrModelDate);
+ EXPECT_EQ(2019, date.year);
+ }
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getHisenseTvEdid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("Hisense", info.name.data());
+ EXPECT_STREQ("HEC", info.manufacturerPnpId.data());
+ EXPECT_STREQ("0", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
+ const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
+ EXPECT_EQ(2019, date.year);
+ EXPECT_EQ(18, date.week);
+ }
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getCtlDisplayEdid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("LP2361", info.name.data());
+ EXPECT_STREQ("CTL", info.manufacturerPnpId.data());
+ EXPECT_STREQ("9373", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ModelYear>(info.manufactureOrModelDate));
+ EXPECT_EQ(2013, std::get<ModelYear>(info.manufactureOrModelDate).year);
+ }
+}
+
TEST(DisplayIdentificationTest, getFallbackDisplayId) {
// Manufacturer ID should be invalid.
ASSERT_FALSE(getPnpId(getFallbackDisplayId(0)));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 99c5f3d..7e62513 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -247,7 +247,7 @@
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
}
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_60_90) {
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -261,100 +261,136 @@
auto& lr = layers[0];
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "Min";
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "Max";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "90Hz Heuristic";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 60.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "60Hz Heuristic";
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 45.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "45Hz Heuristic";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 30.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "30Hz Heuristic";
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 24.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "24Hz Heuristic";
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ lr.name = "";
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 60.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 45.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 30.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 24.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 60.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 45.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 30.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 24.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0);
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 60.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 45.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 30.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 24.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
}
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_60_72_90) {
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_72_90) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
@@ -370,29 +406,36 @@
auto& lr = layers[0];
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 60.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 45.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 30.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 24.0f;
- EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected72Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
}
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60_72_90_120) {
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90_120) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -417,23 +460,25 @@
lr1.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 60.0f;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected120Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 48.0f;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected72Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 48.0f;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected72Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
}
-TEST_F(RefreshRateConfigsTest,
- twoDeviceConfigs_getRefreshRateForContentV2_30_60_90_120_DifferentTypes) {
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_DifferentTypes) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -456,54 +501,87 @@
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.name = "24Hz ExplicitDefault";
lr2.desiredRefreshRate = 60.0f;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "60Hz Heuristic";
+ EXPECT_EQ(expected120Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
lr2.desiredRefreshRate = 60.0f;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "60Hz Heuristic";
+ EXPECT_EQ(expected120Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
lr2.desiredRefreshRate = 60.0f;
lr2.vote = LayerVoteType::ExplicitDefault;
- EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "60Hz ExplicitDefault";
+ EXPECT_EQ(expected120Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
lr2.desiredRefreshRate = 90.0f;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(expected72Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.name = "24Hz ExplicitDefault";
lr2.desiredRefreshRate = 90.0f;
lr2.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::Heuristic;
+ lr1.name = "24Hz Heuristic";
lr2.desiredRefreshRate = 90.0f;
lr2.vote = LayerVoteType::ExplicitDefault;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "90Hz ExplicitDefault";
+ EXPECT_EQ(expected72Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
lr2.desiredRefreshRate = 90.0f;
lr2.vote = LayerVoteType::ExplicitDefault;
- EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "90Hz ExplicitDefault";
+ EXPECT_EQ(expected72Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.name = "24Hz ExplicitDefault";
lr2.desiredRefreshRate = 90.0f;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "90Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
}
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60) {
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}}};
@@ -517,29 +595,36 @@
auto& lr = layers[0];
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected30Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 60.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 45.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 30.0f;
- EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected30Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 24.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
}
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60_72_90) {
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -557,29 +642,59 @@
auto& lr = layers[0];
lr.vote = LayerVoteType::Min;
- EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "Min";
+ EXPECT_EQ(expected30Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.vote = LayerVoteType::Max;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "Max";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "90Hz Heuristic";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr.desiredRefreshRate = 60.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "60Hz Heuristic";
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
lr.desiredRefreshRate = 45.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "45Hz Heuristic";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
lr.desiredRefreshRate = 30.0f;
- EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "30Hz Heuristic";
+ EXPECT_EQ(expected30Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
lr.desiredRefreshRate = 24.0f;
- EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr.name = "24Hz Heuristic";
+ EXPECT_EQ(expected72Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
+
+ lr.desiredRefreshRate = 24.0f;
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr.name = "24Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(expected72Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
}
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_PriorityTest) {
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_PriorityTest) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -598,42 +713,49 @@
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::Max;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 24.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 24.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 60.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 15.0f;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 45.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 30.0f;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 45.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
}
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_24FpsVideo) {
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_24FpsVideo) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -650,7 +772,8 @@
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
lr.desiredRefreshRate = fps;
- const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers);
+ const auto& refreshRate =
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false);
printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str());
EXPECT_EQ(expected60Config, refreshRate);
}
@@ -703,13 +826,22 @@
lr1.desiredRefreshRate = 60.0f;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 90.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 90.0f;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
}
TEST_F(RefreshRateConfigsTest, testInPolicy) {
@@ -722,7 +854,7 @@
ASSERT_FALSE(expectedDefaultConfig.inPolicy(50.0f, 59.998f));
}
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_75HzContent) {
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_75HzContent) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -739,13 +871,14 @@
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
lr.desiredRefreshRate = fps;
- const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers);
+ const auto& refreshRate =
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false);
printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str());
EXPECT_EQ(expected90Config, refreshRate);
}
}
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Multiples) {
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -762,25 +895,99 @@
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 90.0f;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.name = "90Hz ExplicitDefault";
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "Max";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 30.0f;
+ lr1.name = "30Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 90.0f;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 30.0f;
+ lr1.name = "30Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ lr2.name = "Max";
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+}
+
+TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::NoVote;
+ lr2.name = "NoVote";
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::NoVote;
+ lr2.name = "NoVote";
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, true));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Max;
+ lr2.name = "Max";
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, true));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Max;
+ lr2.name = "Max";
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false));
+
+ // The other layer starts to provide buffers
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false));
}
} // namespace
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 7e988a1..aae72db 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -124,8 +124,7 @@
};
void AddImplicitLayers() {
- if (!is_instance_ ||
- !android::GraphicsEnv::getInstance().isDebuggable())
+ if (!is_instance_)
return;
GetLayersFromSettings();