Merge "Enable per-device GPU clock configuration"
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 3713e87..02e5d9b 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);
@@ -1101,7 +1103,7 @@
binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
- const std::string& dataAppName, int32_t appId, const std::string& seInfo,
+ int32_t appId, const std::string& seInfo,
int32_t targetSdkVersion, const std::string& fromCodePath) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(fromUuid);
@@ -1112,24 +1114,24 @@
const char* from_uuid = fromUuid ? fromUuid->c_str() : nullptr;
const char* to_uuid = toUuid ? toUuid->c_str() : nullptr;
const char* package_name = packageName.c_str();
- const char* data_app_name = dataAppName.c_str();
binder::Status res = ok();
std::vector<userid_t> users = get_known_users(from_uuid);
+ auto to_app_package_path_parent = create_data_app_path(to_uuid);
+ auto to_app_package_path = StringPrintf("%s/%s", to_app_package_path_parent.c_str(),
+ android::base::Basename(fromCodePath).c_str());
+
// Copy app
{
- auto to = create_data_app_package_path(to_uuid, data_app_name);
- auto to_parent = create_data_app_path(to_uuid);
-
- int rc = copy_directory_recursive(fromCodePath.c_str(), to_parent.c_str());
+ int rc = copy_directory_recursive(fromCodePath.c_str(), to_app_package_path_parent.c_str());
if (rc != 0) {
- res = error(rc, "Failed copying " + fromCodePath + " to " + to);
+ res = error(rc, "Failed copying " + fromCodePath + " to " + to_app_package_path);
goto fail;
}
- if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
- res = error("Failed to restorecon " + to);
+ if (selinux_android_restorecon(to_app_package_path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+ res = error("Failed to restorecon " + to_app_package_path);
goto fail;
}
}
@@ -1186,9 +1188,8 @@
fail:
// Nuke everything we might have already copied
{
- auto to = create_data_app_package_path(to_uuid, data_app_name);
- if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
- LOG(WARNING) << "Failed to rollback " << to;
+ if (delete_dir_contents(to_app_package_path.c_str(), 1, nullptr) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to_app_package_path;
}
}
for (auto user : users) {
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 27c59b0..df01c3c 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -96,7 +96,7 @@
binder::Status moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
- const std::string& dataAppName, int32_t appId, const std::string& seInfo,
+ int32_t appId, const std::string& seInfo,
int32_t targetSdkVersion, const std::string& fromCodePath);
binder::Status dexopt(const std::string& apkPath, int32_t uid,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index f2e86ba..ca95cb3 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -51,7 +51,7 @@
void setAppQuota(@nullable @utf8InCpp String uuid, int userId, int appId, long cacheQuota);
void moveCompleteApp(@nullable @utf8InCpp String fromUuid, @nullable @utf8InCpp String toUuid,
- @utf8InCpp String packageName, @utf8InCpp String dataAppName, int appId,
+ @utf8InCpp String packageName, int appId,
@utf8InCpp String seInfo, int targetSdkVersion, @utf8InCpp String fromCodePath);
void dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName,
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index d236f76..ed87b67 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -331,13 +331,6 @@
create_data_media_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10));
}
-TEST_F(UtilsTest, CreateDataAppPackagePath) {
- EXPECT_EQ("/data/app/com.example", create_data_app_package_path(nullptr, "com.example"));
-
- EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app/com.example",
- create_data_app_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example"));
-}
-
TEST_F(UtilsTest, CreateDataUserPackagePath) {
EXPECT_EQ("/data/data/com.example", create_data_user_ce_package_path(nullptr, 0, "com.example"));
EXPECT_EQ("/data/user/10/com.example", create_data_user_ce_package_path(nullptr, 10, "com.example"));
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 939cf90..042d69e 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -100,18 +100,6 @@
}
/**
- * Create the path name where package app contents should be stored for
- * the given volume UUID and package name. An empty UUID is assumed to
- * be internal storage.
- */
-std::string create_data_app_package_path(const char* volume_uuid,
- const char* package_name) {
- check_package_name(package_name);
- return StringPrintf("%s/%s",
- create_data_app_path(volume_uuid).c_str(), package_name);
-}
-
-/**
* Create the path name where package data should be stored for the given
* volume UUID, package name, and user ID. An empty UUID is assumed to be
* internal storage.
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 6a39adc..01126c0 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -47,7 +47,6 @@
std::string create_data_path(const char* volume_uuid);
std::string create_data_app_path(const char* volume_uuid);
-std::string create_data_app_package_path(const char* volume_uuid, const char* package_name);
std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid);
std::string create_data_user_de_path(const char* volume_uuid, userid_t userid);
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/include/input/InputDevice.h b/include/input/InputDevice.h
index b6efc82..20a17e3 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -180,6 +180,8 @@
VIRTUAL_KEYBOARD_ID = -1,
// Device id of the "built-in" keyboard if there is one.
BUILT_IN_KEYBOARD_ID = 0,
+ // First device id available for dynamic devices
+ END_RESERVED_ID = 1,
};
} // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index bdc2e40..4b773e8 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -112,6 +112,10 @@
{
sp<IBinder> context = getStrongProxyForHandle(0);
+ if (context == nullptr) {
+ ALOGW("Not able to get context object on %s.", mDriverName.c_str());
+ }
+
// The root object is special since we get it directly from the driver, it is never
// written by Parcell::writeStrongBinder.
internal::Stability::tryMarkCompilationUnit(context.get());
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..c33c44f 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"
@@ -246,15 +247,12 @@
if (fd != -1) {
return STATUS_UNKNOWN_ERROR;
}
- return parcel->get()->writeInt32(0); // null
+ return PruneStatusT(parcel->get()->writeInt32(0)); // null
}
+ status_t status = parcel->get()->writeInt32(1); // not-null
+ if (status != STATUS_OK) return PruneStatusT(status);
- ParcelFileDescriptor parcelFd = ParcelFileDescriptor(unique_fd(fd));
- status_t status = parcel->get()->writeParcelable(parcelFd);
-
- // ownership is retained by caller
- (void)parcelFd.release().release();
-
+ status = parcel->get()->writeDupParcelFileDescriptor(fd);
return PruneStatusT(status);
}
@@ -645,4 +643,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/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 90fded0..1b42b69 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -35,7 +35,7 @@
"/system/bin/mediaserver",
"/system/bin/netd",
"/system/bin/sdcard",
- "/system/bin/statsd",
+ "/apex/com.android.os.statsd/bin/statsd",
"/system/bin/surfaceflinger",
"/system/bin/vehicle_network_service",
"/vendor/bin/hw/android.hardware.media.omx@1.0-service", // media.codec
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/Android.bp b/services/inputflinger/Android.bp
index 5c80d55..439d9bf 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// Default flags to be used throughout all libraries in inputflinger.
cc_defaults {
name: "inputflinger_defaults",
cflags: [
@@ -23,22 +24,25 @@
],
}
-cc_library_shared {
- name: "libinputflinger",
- defaults: ["inputflinger_defaults"],
+/////////////////////////////////////////////////
+// libinputflinger
+/////////////////////////////////////////////////
+filegroup {
+ name: "libinputflinger_sources",
srcs: [
"InputClassifier.cpp",
"InputClassifierConverter.cpp",
"InputManager.cpp",
],
+}
+cc_defaults {
+ name: "libinputflinger_defaults",
+ srcs: [":libinputflinger_sources"],
shared_libs: [
"android.hardware.input.classifier@1.0",
"libbase",
- "libinputflinger_base",
- "libinputreporter",
- "libinputreader",
"libbinder",
"libcrypto",
"libcutils",
@@ -50,60 +54,76 @@
"libui",
"server_configurable_flags",
],
+}
- static_libs: [
- "libinputdispatcher",
+cc_library_shared {
+ name: "libinputflinger",
+ defaults: [
+ "inputflinger_defaults",
+ "libinputflinger_defaults",
],
-
cflags: [
// TODO(b/23084678): Move inputflinger to its own process and mark it hidden
//-fvisibility=hidden
],
-
+ shared_libs: [
+ // This should consist only of dependencies from inputflinger. Other dependencies should be
+ // in cc_defaults so that they are included in the tests.
+ "libinputflinger_base",
+ "libinputreporter",
+ "libinputreader",
+ ],
+ static_libs: [
+ "libinputdispatcher",
+ ],
+ export_static_lib_headers: [
+ "libinputdispatcher",
+ ],
export_include_dirs: [
".",
"include",
],
-
- export_static_lib_headers: [
- "libinputdispatcher",
- ],
}
+/////////////////////////////////////////////////
+// libinputflinger_base
+/////////////////////////////////////////////////
+
cc_library_headers {
name: "libinputflinger_headers",
- header_libs: ["libinputreporter_headers"],
export_include_dirs: ["include"],
- export_header_lib_headers: ["libinputreporter_headers"],
}
-cc_library_shared {
- name: "libinputflinger_base",
- defaults: ["inputflinger_defaults"],
-
+filegroup {
+ name: "libinputflinger_base_sources",
srcs: [
"InputListener.cpp",
"InputReaderBase.cpp",
"InputThread.cpp",
],
+}
+cc_defaults {
+ name: "libinputflinger_base_defaults",
+ srcs: [":libinputflinger_base_sources"],
shared_libs: [
"libbase",
"libinput",
"liblog",
"libutils",
],
-
header_libs: [
"libinputflinger_headers",
],
-
- export_header_lib_headers: [
- "libinputflinger_headers",
- ],
}
-subdirs = [
- "host",
- "tests",
-]
+cc_library_shared {
+ name: "libinputflinger_base",
+ defaults: [
+ "inputflinger_defaults",
+ "libinputflinger_base_defaults",
+ ],
+ export_header_lib_headers: [
+ "libinputflinger_headers",
+ ],
+}
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/Android.bp b/services/inputflinger/dispatcher/Android.bp
index 3f956a8..a98f4b4 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -12,9 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-cc_library_static {
- name: "libinputdispatcher",
- defaults: ["inputflinger_defaults"],
+cc_library_headers {
+ name: "libinputdispatcher_headers",
+ export_include_dirs: [
+ "include",
+ ],
+}
+
+filegroup {
+ name: "libinputdispatcher_sources",
srcs: [
"Connection.cpp",
"Entry.cpp",
@@ -24,20 +30,41 @@
"InputState.cpp",
"InputTarget.cpp",
"Monitor.cpp",
- "TouchState.cpp"
+ "TouchState.cpp",
],
+}
+
+cc_defaults {
+ name: "libinputdispatcher_defaults",
+ srcs: [":libinputdispatcher_sources"],
shared_libs: [
"libbase",
"libcrypto",
"libcutils",
"libinput",
- "libinputreporter",
- "libinputflinger_base",
"liblog",
"libstatslog",
"libui",
"libutils",
],
+ header_libs: [
+ "libinputdispatcher_headers",
+ ],
+}
- export_include_dirs: ["include"],
+cc_library_static {
+ name: "libinputdispatcher",
+ defaults: [
+ "inputflinger_defaults",
+ "libinputdispatcher_defaults",
+ ],
+ shared_libs: [
+ // This should consist only of dependencies from inputflinger. Other dependencies should be
+ // in cc_defaults so that they are included in the tests.
+ "libinputreporter",
+ "libinputflinger_base",
+ ],
+ export_header_lib_headers: [
+ "libinputdispatcher_headers",
+ ],
}
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/Android.bp b/services/inputflinger/reader/Android.bp
index 23c08b2..83a610f 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -21,10 +21,8 @@
],
}
-cc_library_shared {
- name: "libinputreader",
- defaults: ["inputflinger_defaults"],
-
+filegroup {
+ name: "libinputreader_sources",
srcs: [
"EventHub.cpp",
"InputDevice.cpp",
@@ -44,14 +42,16 @@
"mapper/TouchInputMapper.cpp",
"mapper/VibratorInputMapper.cpp",
"InputReader.cpp",
- "InputReaderFactory.cpp",
"TouchVideoDevice.cpp",
],
+}
+cc_defaults {
+ name: "libinputreader_defaults",
+ srcs: [":libinputreader_sources"],
shared_libs: [
"libbase",
"libcap",
- "libinputflinger_base",
"libcrypto",
"libcutils",
"libinput",
@@ -59,13 +59,26 @@
"libui",
"libutils",
],
-
header_libs: [
- "libinputflinger_headers",
"libinputreader_headers",
],
+}
+cc_library_shared {
+ name: "libinputreader",
+ defaults: [
+ "inputflinger_defaults",
+ "libinputreader_defaults"
+ ],
+ srcs: [
+ "InputReaderFactory.cpp",
+ ],
+ shared_libs: [
+ // This should consist only of dependencies from inputflinger. Other dependencies should be
+ // in cc_defaults so that they are included in the tests.
+ "libinputflinger_base",
+ ],
export_header_lib_headers: [
- "libinputflinger_headers",
+ "libinputreader_headers",
],
}
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index ae82cd4..d0eee64 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -18,6 +18,8 @@
#include "InputDevice.h"
+#include <algorithm>
+
#include "CursorInputMapper.h"
#include "ExternalStylusInputMapper.h"
#include "InputReaderContext.h"
@@ -32,25 +34,28 @@
namespace android {
InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
- int32_t controllerNumber, const InputDeviceIdentifier& identifier,
- uint32_t classes)
+ const InputDeviceIdentifier& identifier)
: mContext(context),
mId(id),
mGeneration(generation),
- mControllerNumber(controllerNumber),
+ mControllerNumber(0),
mIdentifier(identifier),
- mClasses(classes),
+ mClasses(0),
mSources(0),
mIsExternal(false),
mHasMic(false),
- mDropUntilNextSync(false) {
- mDeviceContext = std::make_unique<InputDeviceContext>(*this);
-}
+ mDropUntilNextSync(false) {}
InputDevice::~InputDevice() {}
bool InputDevice::isEnabled() {
- return mDeviceContext->isDeviceEnabled();
+ if (!hasEventHubDevices()) {
+ return false;
+ }
+ // devices are either all enabled or all disabled, so we only need to check the first
+ auto& devicePair = mDevices.begin()->second;
+ auto& contextPtr = devicePair.first;
+ return contextPtr->isDeviceEnabled();
}
void InputDevice::setEnabled(bool enabled, nsecs_t when) {
@@ -65,12 +70,15 @@
return;
}
+ // When resetting some devices, the driver needs to be queried to ensure that a proper reset is
+ // performed. The querying must happen when the device is enabled, so we reset after enabling
+ // but before disabling the device. See MultiTouchMotionAccumulator::reset for more information.
if (enabled) {
- mDeviceContext->enableDevice();
+ for_each_subdevice([](auto& context) { context.enableDevice(); });
reset(when);
} else {
reset(when);
- mDeviceContext->disableDevice();
+ for_each_subdevice([](auto& context) { context.disableDevice(); });
}
// Must change generation to flag this device as changed
bumpGeneration();
@@ -118,19 +126,18 @@
for_each_mapper([&dump](InputMapper& mapper) { mapper.dump(dump); });
}
-void InputDevice::populateMappers() {
- uint32_t classes = mClasses;
- std::vector<std::unique_ptr<InputMapper>>& mappers = mMappers;
- std::unique_ptr<InputDeviceContext>& contextPtr = mDeviceContext;
-
- // External devices.
- if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
- setExternal(true);
+void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
+ if (mDevices.find(eventHubId) != mDevices.end()) {
+ return;
}
+ std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
+ uint32_t classes = contextPtr->getDeviceClasses();
+ std::vector<std::unique_ptr<InputMapper>> mappers;
- // Devices with mics.
- if (classes & INPUT_DEVICE_CLASS_MIC) {
- setMic(true);
+ // Check if we should skip population
+ if (!populateMappers) {
+ mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
+ return;
}
// Switch-like devices.
@@ -190,22 +197,58 @@
if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
mappers.push_back(std::make_unique<ExternalStylusInputMapper>(*contextPtr));
}
+
+ // insert the context into the devices set
+ mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
+}
+
+void InputDevice::removeEventHubDevice(int32_t eventHubId) {
+ mDevices.erase(eventHubId);
}
void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config,
uint32_t changes) {
mSources = 0;
+ mClasses = 0;
+ mControllerNumber = 0;
+
+ for_each_subdevice([this](InputDeviceContext& context) {
+ mClasses |= context.getDeviceClasses();
+ int32_t controllerNumber = context.getDeviceControllerNumber();
+ if (controllerNumber > 0) {
+ if (mControllerNumber && mControllerNumber != controllerNumber) {
+ ALOGW("InputDevice::configure(): composite device contains multiple unique "
+ "controller numbers");
+ }
+ mControllerNumber = controllerNumber;
+ }
+ });
+
+ mIsExternal = !!(mClasses & INPUT_DEVICE_CLASS_EXTERNAL);
+ mHasMic = !!(mClasses & INPUT_DEVICE_CLASS_MIC);
if (!isIgnored()) {
if (!changes) { // first time only
- mDeviceContext->getConfiguration(&mConfiguration);
+ mConfiguration.clear();
+ for_each_subdevice([this](InputDeviceContext& context) {
+ PropertyMap configuration;
+ context.getConfiguration(&configuration);
+ mConfiguration.addAll(&configuration);
+ });
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) {
if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
sp<KeyCharacterMap> keyboardLayout =
mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier);
- if (mDeviceContext->setKeyboardLayoutOverlay(keyboardLayout)) {
+ bool shouldBumpGeneration = false;
+ for_each_subdevice(
+ [&keyboardLayout, &shouldBumpGeneration](InputDeviceContext& context) {
+ if (context.setKeyboardLayoutOverlay(keyboardLayout)) {
+ shouldBumpGeneration = true;
+ }
+ });
+ if (shouldBumpGeneration) {
bumpGeneration();
}
}
@@ -313,7 +356,9 @@
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
- for_each_mapper([rawEvent](InputMapper& mapper) { mapper.process(rawEvent); });
+ for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
+ mapper.process(rawEvent);
+ });
}
--count;
}
@@ -348,16 +393,20 @@
int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) {
int32_t result = AKEY_STATE_UNKNOWN;
- for (auto& mapperPtr : mMappers) {
- InputMapper& mapper = *mapperPtr;
- if (sourcesMatchMask(mapper.getSources(), sourceMask)) {
- // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
- // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it.
- int32_t currentResult = (mapper.*getStateFunc)(sourceMask, code);
- if (currentResult >= AKEY_STATE_DOWN) {
- return currentResult;
- } else if (currentResult == AKEY_STATE_UP) {
- result = currentResult;
+ for (auto& deviceEntry : mDevices) {
+ auto& devicePair = deviceEntry.second;
+ auto& mappers = devicePair.second;
+ for (auto& mapperPtr : mappers) {
+ InputMapper& mapper = *mapperPtr;
+ if (sourcesMatchMask(mapper.getSources(), sourceMask)) {
+ // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
+ // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it.
+ int32_t currentResult = (mapper.*getStateFunc)(sourceMask, code);
+ if (currentResult >= AKEY_STATE_DOWN) {
+ return currentResult;
+ } else if (currentResult == AKEY_STATE_UP) {
+ result = currentResult;
+ }
}
}
}
@@ -424,11 +473,23 @@
[](InputMapper& mapper) { return mapper.getAssociatedDisplayId(); });
}
-InputDeviceContext::InputDeviceContext(InputDevice& device)
+// returns the number of mappers associated with the device
+size_t InputDevice::getMapperCount() {
+ size_t count = 0;
+ for (auto& deviceEntry : mDevices) {
+ auto& devicePair = deviceEntry.second;
+ auto& mappers = devicePair.second;
+ count += mappers.size();
+ }
+ return count;
+}
+
+InputDeviceContext::InputDeviceContext(InputDevice& device, int32_t eventHubId)
: mDevice(device),
mContext(device.getContext()),
mEventHub(device.getContext()->getEventHub()),
- mId(device.getId()) {}
+ mId(eventHubId),
+ mDeviceId(device.getId()) {}
InputDeviceContext::~InputDeviceContext() {}
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 3e23fa6..cbfa702 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -49,6 +49,7 @@
mNextSequenceNum(1),
mGlobalMetaState(0),
mGeneration(1),
+ mNextInputDeviceId(END_RESERVED_ID),
mDisableVirtualKeysTimeout(LLONG_MIN),
mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
@@ -62,11 +63,7 @@
} // release lock
}
-InputReader::~InputReader() {
- for (auto& devicePair : mDevices) {
- delete devicePair.second;
- }
-}
+InputReader::~InputReader() {}
status_t InputReader::start() {
if (mThread) {
@@ -188,29 +185,28 @@
}
}
-void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
- if (mDevices.find(deviceId) != mDevices.end()) {
- ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
+void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
+ if (mDevices.find(eventHubId) != mDevices.end()) {
+ ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);
return;
}
- InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
- uint32_t classes = mEventHub->getDeviceClasses(deviceId);
- int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
-
- InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
+ InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
+ std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);
device->configure(when, &mConfig, 0);
device->reset(when);
if (device->isIgnored()) {
- ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
- identifier.name.c_str());
+ ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s' "
+ "(ignored non-input device)",
+ device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str());
} else {
- ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, identifier.name.c_str(),
+ ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s',sources=0x%08x",
+ device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str(),
device->getSources());
}
- mDevices.insert({deviceId, device});
+ mDevices.emplace(eventHubId, device);
bumpGenerationLocked();
if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
@@ -218,51 +214,68 @@
}
}
-void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
- auto deviceIt = mDevices.find(deviceId);
+void InputReader::removeDeviceLocked(nsecs_t when, int32_t eventHubId) {
+ auto deviceIt = mDevices.find(eventHubId);
if (deviceIt == mDevices.end()) {
- ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId);
+ ALOGW("Ignoring spurious device removed event for eventHubId %d.", eventHubId);
return;
}
- InputDevice* device = deviceIt->second;
+ std::shared_ptr<InputDevice> device = std::move(deviceIt->second);
mDevices.erase(deviceIt);
bumpGenerationLocked();
if (device->isIgnored()) {
- ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", device->getId(),
- device->getName().c_str());
+ ALOGI("Device removed: id=%d, eventHubId=%d, name='%s', descriptor='%s' "
+ "(ignored non-input device)",
+ device->getId(), eventHubId, device->getName().c_str(),
+ device->getDescriptor().c_str());
} else {
- ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", device->getId(),
- device->getName().c_str(), device->getSources());
+ ALOGI("Device removed: id=%d, eventHubId=%d, name='%s', descriptor='%s', sources=0x%08x",
+ device->getId(), eventHubId, device->getName().c_str(),
+ device->getDescriptor().c_str(), device->getSources());
}
+ device->removeEventHubDevice(eventHubId);
+
if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
notifyExternalStylusPresenceChanged();
}
+ if (device->hasEventHubDevices()) {
+ device->configure(when, &mConfig, 0);
+ }
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(),
- controllerNumber, identifier, classes);
- device->populateMappers();
+std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
+ int32_t eventHubId, const InputDeviceIdentifier& identifier) {
+ auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {
+ return devicePair.second->getDescriptor().size() && identifier.descriptor.size() &&
+ devicePair.second->getDescriptor() == identifier.descriptor;
+ });
+
+ std::shared_ptr<InputDevice> device;
+ if (deviceIt != mDevices.end()) {
+ device = deviceIt->second;
+ } else {
+ int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();
+ device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
+ identifier);
+ }
+ device->addEventHubDevice(eventHubId);
return device;
}
-void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents,
+void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
size_t count) {
- auto deviceIt = mDevices.find(deviceId);
+ auto deviceIt = mDevices.find(eventHubId);
if (deviceIt == mDevices.end()) {
- ALOGW("Discarding event for unknown deviceId %d.", deviceId);
+ ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
return;
}
- InputDevice* device = deviceIt->second;
+ std::shared_ptr<InputDevice>& device = deviceIt->second;
if (device->isIgnored()) {
// ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
@@ -271,15 +284,30 @@
device->process(rawEvents, count);
}
+InputDevice* InputReader::findInputDevice(int32_t deviceId) {
+ auto deviceIt =
+ std::find_if(mDevices.begin(), mDevices.end(), [deviceId](const auto& devicePair) {
+ return devicePair.second->getId() == deviceId;
+ });
+ if (deviceIt != mDevices.end()) {
+ return deviceIt->second.get();
+ }
+ return nullptr;
+}
+
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);
}
}
}
+int32_t InputReader::nextInputDeviceIdLocked() {
+ return ++mNextInputDeviceId;
+}
+
void InputReader::handleConfigurationChangedLocked(nsecs_t when) {
// Reset global meta state because it depends on the list of all configured devices.
updateGlobalMetaStateLocked();
@@ -302,7 +330,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 +341,7 @@
mGlobalMetaState = 0;
for (auto& devicePair : mDevices) {
- InputDevice* device = devicePair.second;
+ std::shared_ptr<InputDevice>& device = devicePair.second;
mGlobalMetaState |= device->getMetaState();
}
}
@@ -328,7 +356,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 +367,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 +389,7 @@
void InputReader::fadePointerLocked() {
for (auto& devicePair : mDevices) {
- InputDevice* device = devicePair.second;
+ std::shared_ptr<InputDevice>& device = devicePair.second;
device->fadePointer();
}
}
@@ -386,7 +414,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);
@@ -417,20 +445,17 @@
GetStateFunc getStateFunc) {
int32_t result = AKEY_STATE_UNKNOWN;
if (deviceId >= 0) {
- auto deviceIt = mDevices.find(deviceId);
- if (deviceIt != mDevices.end()) {
- InputDevice* device = deviceIt->second;
- if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
- result = (device->*getStateFunc)(sourceMask, code);
- }
+ InputDevice* device = findInputDevice(deviceId);
+ if (device && !device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
+ result = (device->*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) {
@@ -443,13 +468,12 @@
}
void InputReader::toggleCapsLockState(int32_t deviceId) {
- auto deviceIt = mDevices.find(deviceId);
- if (deviceIt == mDevices.end()) {
+ InputDevice* device = findInputDevice(deviceId);
+ if (!device) {
ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId);
return;
}
- InputDevice* device = deviceIt->second;
if (device->isIgnored()) {
return;
}
@@ -470,16 +494,13 @@
uint8_t* outFlags) {
bool result = false;
if (deviceId >= 0) {
- auto deviceIt = mDevices.find(deviceId);
- if (deviceIt != mDevices.end()) {
- InputDevice* device = deviceIt->second;
- if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
- result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
- }
+ InputDevice* device = findInputDevice(deviceId);
+ if (device && !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);
}
@@ -504,9 +525,8 @@
void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
ssize_t repeat, int32_t token) {
AutoMutex _l(mLock);
- auto deviceIt = mDevices.find(deviceId);
- if (deviceIt != mDevices.end()) {
- InputDevice* device = deviceIt->second;
+ InputDevice* device = findInputDevice(deviceId);
+ if (device) {
device->vibrate(pattern, patternSize, repeat, token);
}
}
@@ -514,9 +534,8 @@
void InputReader::cancelVibrate(int32_t deviceId, int32_t token) {
AutoMutex _l(mLock);
- auto deviceIt = mDevices.find(deviceId);
- if (deviceIt != mDevices.end()) {
- InputDevice* device = deviceIt->second;
+ InputDevice* device = findInputDevice(deviceId);
+ if (device) {
device->cancelVibrate(token);
}
}
@@ -524,9 +543,8 @@
bool InputReader::isInputDeviceEnabled(int32_t deviceId) {
AutoMutex _l(mLock);
- auto deviceIt = mDevices.find(deviceId);
- if (deviceIt != mDevices.end()) {
- InputDevice* device = deviceIt->second;
+ InputDevice* device = findInputDevice(deviceId);
+ if (device) {
return device->isEnabled();
}
ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId);
@@ -536,13 +554,12 @@
bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) {
AutoMutex _l(mLock);
- auto deviceIt = mDevices.find(deviceId);
- if (deviceIt == mDevices.end()) {
+ InputDevice* device = findInputDevice(deviceId);
+ if (!device) {
ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId);
return false;
}
- InputDevice* device = deviceIt->second;
if (!device->isEnabled()) {
ALOGW("Ignoring disabled device %s", device->getName().c_str());
return false;
@@ -571,7 +588,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/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 0814d1f..aaa0d26 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -17,18 +17,19 @@
#ifndef _UI_INPUTREADER_INPUT_DEVICE_H
#define _UI_INPUTREADER_INPUT_DEVICE_H
+#include <input/DisplayViewport.h>
+#include <input/InputDevice.h>
+#include <stdint.h>
+#include <utils/PropertyMap.h>
+
+#include <optional>
+#include <unordered_map>
+#include <vector>
+
#include "EventHub.h"
#include "InputReaderBase.h"
#include "InputReaderContext.h"
-#include <input/DisplayViewport.h>
-#include <input/InputDevice.h>
-#include <utils/PropertyMap.h>
-
-#include <stdint.h>
-#include <optional>
-#include <vector>
-
namespace android {
class InputDeviceContext;
@@ -38,8 +39,7 @@
class InputDevice {
public:
InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
- int32_t controllerNumber, const InputDeviceIdentifier& identifier,
- uint32_t classes);
+ const InputDeviceIdentifier& identifier);
~InputDevice();
inline InputReaderContext* getContext() { return mContext; }
@@ -50,25 +50,25 @@
inline const std::string getDescriptor() { return mIdentifier.descriptor; }
inline uint32_t getClasses() const { return mClasses; }
inline uint32_t getSources() const { return mSources; }
+ inline bool hasEventHubDevices() const { return !mDevices.empty(); }
inline bool isExternal() { return mIsExternal; }
- inline void setExternal(bool external) { mIsExternal = external; }
inline std::optional<uint8_t> getAssociatedDisplayPort() const {
return mAssociatedDisplayPort;
}
inline std::optional<DisplayViewport> getAssociatedViewport() const {
return mAssociatedViewport;
}
- inline void setMic(bool hasMic) { mHasMic = hasMic; }
inline bool hasMic() const { return mHasMic; }
- inline bool isIgnored() { return mMappers.empty(); }
+ inline bool isIgnored() { return !getMapperCount(); }
bool isEnabled();
void setEnabled(bool enabled, nsecs_t when);
void dump(std::string& dump);
- void populateMappers();
+ void addEventHubDevice(int32_t eventHubId, bool populateMappers = true);
+ void removeEventHubDevice(int32_t eventHubId);
void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
void reset(nsecs_t when);
void process(const RawEvent* rawEvents, size_t count);
@@ -99,11 +99,20 @@
std::optional<int32_t> getAssociatedDisplayId();
+ size_t getMapperCount();
+
// construct and add a mapper to the input device
template <class T, typename... Args>
- T& addMapper(Args... args) {
- T* mapper = new T(*mDeviceContext, args...);
- mMappers.emplace_back(mapper);
+ T& addMapper(int32_t eventHubId, Args... args) {
+ // ensure a device entry exists for this eventHubId
+ addEventHubDevice(eventHubId, false);
+
+ // create mapper
+ auto& devicePair = mDevices[eventHubId];
+ auto& deviceContext = devicePair.first;
+ auto& mappers = devicePair.second;
+ T* mapper = new T(*deviceContext, args...);
+ mappers.emplace_back(mapper);
return *mapper;
}
@@ -116,8 +125,10 @@
std::string mAlias;
uint32_t mClasses;
- std::unique_ptr<InputDeviceContext> mDeviceContext;
- std::vector<std::unique_ptr<InputMapper>> mMappers;
+ // map from eventHubId to device context and mappers
+ using MapperVector = std::vector<std::unique_ptr<InputMapper>>;
+ using DevicePair = std::pair<std::unique_ptr<InputDeviceContext>, MapperVector>;
+ std::unordered_map<int32_t, DevicePair> mDevices;
uint32_t mSources;
bool mIsExternal;
@@ -131,10 +142,37 @@
PropertyMap mConfiguration;
- // run a function against every mapper
+ // helpers to interate over the devices collection
+ // run a function against every mapper on every subdevice
inline void for_each_mapper(std::function<void(InputMapper&)> f) {
- for (auto& mapperPtr : mMappers) {
- f(*mapperPtr);
+ for (auto& deviceEntry : mDevices) {
+ auto& devicePair = deviceEntry.second;
+ auto& mappers = devicePair.second;
+ for (auto& mapperPtr : mappers) {
+ f(*mapperPtr);
+ }
+ }
+ }
+
+ // run a function against every mapper on a specific subdevice
+ inline void for_each_mapper_in_subdevice(int32_t eventHubDevice,
+ std::function<void(InputMapper&)> f) {
+ auto deviceIt = mDevices.find(eventHubDevice);
+ if (deviceIt != mDevices.end()) {
+ auto& devicePair = deviceIt->second;
+ auto& mappers = devicePair.second;
+ for (auto& mapperPtr : mappers) {
+ f(*mapperPtr);
+ }
+ }
+ }
+
+ // run a function against every subdevice
+ inline void for_each_subdevice(std::function<void(InputDeviceContext&)> f) {
+ for (auto& deviceEntry : mDevices) {
+ auto& devicePair = deviceEntry.second;
+ auto& contextPtr = devicePair.first;
+ f(*contextPtr);
}
}
@@ -142,10 +180,14 @@
// if all mappers return nullopt, return nullopt.
template <typename T>
inline std::optional<T> first_in_mappers(std::function<std::optional<T>(InputMapper&)> f) {
- for (auto& mapperPtr : mMappers) {
- std::optional<T> ret = f(*mapperPtr);
- if (ret) {
- return ret;
+ for (auto& deviceEntry : mDevices) {
+ auto& devicePair = deviceEntry.second;
+ auto& mappers = devicePair.second;
+ for (auto& mapperPtr : mappers) {
+ std::optional<T> ret = f(*mapperPtr);
+ if (ret) {
+ return ret;
+ }
}
}
return std::nullopt;
@@ -159,11 +201,12 @@
*/
class InputDeviceContext {
public:
- InputDeviceContext(InputDevice& device);
+ InputDeviceContext(InputDevice& device, int32_t eventHubId);
~InputDeviceContext();
inline InputReaderContext* getContext() { return mContext; }
- inline int32_t getId() { return mId; }
+ inline int32_t getId() { return mDeviceId; }
+ inline int32_t getEventHubId() { return mId; }
inline uint32_t getDeviceClasses() const { return mEventHub->getDeviceClasses(mId); }
inline InputDeviceIdentifier getDeviceIdentifier() const {
@@ -259,6 +302,7 @@
InputReaderContext* mContext;
EventHubInterface* mEventHub;
int32_t mId;
+ int32_t mDeviceId;
};
} // namespace android
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index cf1af04..31d82f1 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -84,9 +84,8 @@
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, const InputDeviceIdentifier& identifier);
// With each iteration of the loop, InputReader reads and processes one incoming message from
// the EventHub.
@@ -138,14 +137,16 @@
static const int EVENT_BUFFER_SIZE = 256;
RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
- std::unordered_map<int32_t /*deviceId*/, InputDevice*> mDevices;
+ // An input device can represent a collection of EventHub devices. This map provides a way
+ // to lookup the input device instance from the EventHub device id.
+ std::unordered_map<int32_t /*eventHubId*/, std::shared_ptr<InputDevice>> mDevices;
// low-level input event decoding and device management
void processEventsLocked(const RawEvent* rawEvents, size_t count);
- void addDeviceLocked(nsecs_t when, int32_t deviceId);
- void removeDeviceLocked(nsecs_t when, int32_t deviceId);
- void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count);
+ void addDeviceLocked(nsecs_t when, int32_t eventHubId);
+ void removeDeviceLocked(nsecs_t when, int32_t eventHubId);
+ void processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, size_t count);
void timeoutExpiredLocked(nsecs_t when);
void handleConfigurationChangedLocked(nsecs_t when);
@@ -163,6 +164,9 @@
int32_t mGeneration;
int32_t bumpGenerationLocked();
+ int32_t mNextInputDeviceId;
+ int32_t nextInputDeviceIdLocked();
+
void getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices);
nsecs_t mDisableVirtualKeysTimeout;
@@ -181,6 +185,9 @@
GetStateFunc getStateFunc);
bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags);
+
+ // find an InputDevice from an InputDevice id
+ InputDevice* findInputDevice(int32_t deviceId);
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 78f3382..520a4a4 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Macros.h"
+#include "../Macros.h"
#include "CursorInputMapper.h"
diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
index 37e4047..37d1d74 100644
--- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Macros.h"
+#include "../Macros.h"
#include "ExternalStylusInputMapper.h"
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index 92af612..c5f99c9 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Macros.h"
+#include "../Macros.h"
#include "InputMapper.h"
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 57c85b6..7c3b1d9 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Macros.h"
+#include "../Macros.h"
#include "JoystickInputMapper.h"
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 9ab707f..ab354a2 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Macros.h"
+#include "../Macros.h"
#include "KeyboardInputMapper.h"
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index d195a07..d77c8c8 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Macros.h"
+#include "../Macros.h"
#include "MultiTouchInputMapper.h"
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index a1cce56..ed93f14 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Macros.h"
+#include "../Macros.h"
#include "RotaryEncoderInputMapper.h"
diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
index 52b2449..e79aeb2 100644
--- a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Macros.h"
+#include "../Macros.h"
#include "SwitchInputMapper.h"
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index e832804..b3a6df8 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Macros.h"
+#include "../Macros.h"
#include "TouchInputMapper.h"
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index 1b584ea..7665680 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Macros.h"
+#include "../Macros.h"
#include "VibratorInputMapper.h"
diff --git a/services/inputflinger/reporter/Android.bp b/services/inputflinger/reporter/Android.bp
index 5956fb0..fbc51da 100644
--- a/services/inputflinger/reporter/Android.bp
+++ b/services/inputflinger/reporter/Android.bp
@@ -17,25 +17,33 @@
export_include_dirs: ["."],
}
-cc_library_shared {
- name: "libinputreporter",
- defaults: ["inputflinger_defaults"],
-
+filegroup {
+ name: "libinputreporter_sources",
srcs: [
- "InputReporter.cpp",
+ "InputReporter.cpp",
],
+}
+cc_defaults {
+ name: "libinputreporter_defaults",
+ srcs: [":libinputreporter_sources"],
shared_libs: [
"liblog",
"libutils",
],
-
header_libs: [
- "libinputflinger_headers",
+ "libinputreporter_headers",
],
+}
+cc_library_shared {
+ name: "libinputreporter",
+ defaults: [
+ "inputflinger_defaults",
+ "libinputreporter_defaults",
+ ],
export_header_lib_headers: [
- "libinputflinger_headers",
+ "libinputreporter_headers",
],
}
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index f913d82..73d2272 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -1,7 +1,31 @@
-// Build the unit tests.
+// 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.
cc_test {
name: "inputflinger_tests",
+ defaults: [
+ "inputflinger_defaults",
+ // For all targets inside inputflinger, these tests build all of their sources using their
+ // defaults rather than including them as shared or static libraries. By doing so, the tests
+ // will always run against the compiled version of the inputflinger code rather than the
+ // version on the device.
+ "libinputflinger_base_defaults",
+ "libinputreader_defaults",
+ "libinputreporter_defaults",
+ "libinputdispatcher_defaults",
+ "libinputflinger_defaults",
+ ],
srcs: [
"BlockingQueue_test.cpp",
"EventHub_test.cpp",
@@ -12,31 +36,5 @@
"InputReader_test.cpp",
"UinputDevice.cpp",
],
- cflags: [
- "-Wall",
- "-Werror",
- "-Wextra",
- "-Wno-unused-parameter",
- "-Wthread-safety",
- ],
- shared_libs: [
- "android.hardware.input.classifier@1.0",
- "libbase",
- "libbinder",
- "libcutils",
- "liblog",
- "libutils",
- "libhardware",
- "libhardware_legacy",
- "libui",
- "libinput",
- "libinputflinger",
- "libinputreader",
- "libinputflinger_base",
- "libinputservice",
- ],
- header_libs: [
- "libinputreader_headers",
- ],
require_root: true,
}
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..af11256 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,37 +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, const std::string& name,
+ 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, identifier);
}
// 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 eventHubId, const InputDeviceIdentifier& identifier) {
if (mNextDevice) {
- InputDevice* device = mNextDevice;
+ std::shared_ptr<InputDevice> device(mNextDevice);
mNextDevice = nullptr;
return device;
}
- return InputReader::createDeviceLocked(deviceId, controllerNumber, identifier, classes);
+ return InputReader::createDeviceLocked(eventHubId, identifier);
}
friend class InputReaderTest;
@@ -1340,12 +1351,12 @@
mFakePolicy.clear();
}
- void addDevice(int32_t deviceId, const std::string& name, uint32_t classes,
- const PropertyMap* configuration) {
- mFakeEventHub->addDevice(deviceId, name, classes);
+ void addDevice(int32_t eventHubId, const std::string& name, uint32_t classes,
+ const PropertyMap* configuration) {
+ mFakeEventHub->addDevice(eventHubId, name, classes);
if (configuration) {
- mFakeEventHub->addConfigurationMap(deviceId, configuration);
+ mFakeEventHub->addConfigurationMap(eventHubId, configuration);
}
mFakeEventHub->finishDeviceScan();
mReader->loopOnce();
@@ -1364,14 +1375,14 @@
mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_ENABLED_STATE);
}
- FakeInputMapper& addDeviceWithFakeInputMapper(int32_t deviceId, int32_t controllerNumber,
+ FakeInputMapper& addDeviceWithFakeInputMapper(int32_t deviceId, int32_t eventHubId,
const std::string& name, uint32_t classes,
uint32_t sources,
const PropertyMap* configuration) {
- InputDevice* device = mReader->newDevice(deviceId, controllerNumber, name, classes);
- FakeInputMapper& mapper = device->addMapper<FakeInputMapper>(sources);
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, name);
+ FakeInputMapper& mapper = device->addMapper<FakeInputMapper>(eventHubId, sources);
mReader->setNextDevice(device);
- addDevice(deviceId, name, classes, configuration);
+ addDevice(eventHubId, name, classes, configuration);
return mapper;
}
};
@@ -1385,7 +1396,7 @@
std::vector<InputDeviceInfo> inputDevices;
mReader->getInputDevices(inputDevices);
ASSERT_EQ(1U, inputDevices.size());
- ASSERT_EQ(1, inputDevices[0].getId());
+ ASSERT_EQ(END_RESERVED_ID + 1, inputDevices[0].getId());
ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str());
ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType());
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources());
@@ -1394,7 +1405,7 @@
// Should also have received a notification describing the new input devices.
inputDevices = mFakePolicy->getInputDevices();
ASSERT_EQ(1U, inputDevices.size());
- ASSERT_EQ(1, inputDevices[0].getId());
+ ASSERT_EQ(END_RESERVED_ID + 1, inputDevices[0].getId());
ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str());
ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType());
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources());
@@ -1402,13 +1413,14 @@
}
TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
- constexpr int32_t deviceId = 1;
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
+ constexpr int32_t eventHubId = 1;
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
// Must add at least one mapper or the device will be ignored!
- device->addMapper<FakeInputMapper>(AINPUT_SOURCE_KEYBOARD);
+ device->addMapper<FakeInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
mReader->setNextDevice(device);
- ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(nullptr));
@@ -1438,8 +1450,11 @@
}
TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+ constexpr int32_t eventHubId = 1;
FakeInputMapper& mapper =
- addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD,
+ addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
AINPUT_SOURCE_KEYBOARD, nullptr);
mapper.setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
@@ -1447,13 +1462,16 @@
AINPUT_SOURCE_ANY, AKEYCODE_A))
<< "Should return unknown when the device id is >= 0 but unknown.";
- ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(1,
- AINPUT_SOURCE_TRACKBALL, AKEYCODE_A))
- << "Should return unknown when the device id is valid but the sources are not supported by the device.";
+ ASSERT_EQ(AKEY_STATE_UNKNOWN,
+ mReader->getKeyCodeState(deviceId, AINPUT_SOURCE_TRACKBALL, AKEYCODE_A))
+ << "Should return unknown when the device id is valid but the sources are not "
+ "supported by the device.";
- ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(1,
- AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A))
- << "Should return value provided by mapper when device id is valid and the device supports some of the sources.";
+ ASSERT_EQ(AKEY_STATE_DOWN,
+ mReader->getKeyCodeState(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL,
+ AKEYCODE_A))
+ << "Should return value provided by mapper when device id is valid and the device "
+ "supports some of the sources.";
ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(-1,
AINPUT_SOURCE_TRACKBALL, AKEYCODE_A))
@@ -1465,8 +1483,11 @@
}
TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+ constexpr int32_t eventHubId = 1;
FakeInputMapper& mapper =
- addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD,
+ addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
AINPUT_SOURCE_KEYBOARD, nullptr);
mapper.setScanCodeState(KEY_A, AKEY_STATE_DOWN);
@@ -1474,13 +1495,16 @@
AINPUT_SOURCE_ANY, KEY_A))
<< "Should return unknown when the device id is >= 0 but unknown.";
- ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(1,
- AINPUT_SOURCE_TRACKBALL, KEY_A))
- << "Should return unknown when the device id is valid but the sources are not supported by the device.";
+ ASSERT_EQ(AKEY_STATE_UNKNOWN,
+ mReader->getScanCodeState(deviceId, AINPUT_SOURCE_TRACKBALL, KEY_A))
+ << "Should return unknown when the device id is valid but the sources are not "
+ "supported by the device.";
- ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(1,
- AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A))
- << "Should return value provided by mapper when device id is valid and the device supports some of the sources.";
+ ASSERT_EQ(AKEY_STATE_DOWN,
+ mReader->getScanCodeState(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL,
+ KEY_A))
+ << "Should return value provided by mapper when device id is valid and the device "
+ "supports some of the sources.";
ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(-1,
AINPUT_SOURCE_TRACKBALL, KEY_A))
@@ -1492,8 +1516,11 @@
}
TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+ constexpr int32_t eventHubId = 1;
FakeInputMapper& mapper =
- addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD,
+ addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
AINPUT_SOURCE_KEYBOARD, nullptr);
mapper.setSwitchState(SW_LID, AKEY_STATE_DOWN);
@@ -1501,13 +1528,16 @@
AINPUT_SOURCE_ANY, SW_LID))
<< "Should return unknown when the device id is >= 0 but unknown.";
- ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(1,
- AINPUT_SOURCE_TRACKBALL, SW_LID))
- << "Should return unknown when the device id is valid but the sources are not supported by the device.";
+ ASSERT_EQ(AKEY_STATE_UNKNOWN,
+ mReader->getSwitchState(deviceId, AINPUT_SOURCE_TRACKBALL, SW_LID))
+ << "Should return unknown when the device id is valid but the sources are not "
+ "supported by the device.";
- ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(1,
- AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID))
- << "Should return value provided by mapper when device id is valid and the device supports some of the sources.";
+ ASSERT_EQ(AKEY_STATE_DOWN,
+ mReader->getSwitchState(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL,
+ SW_LID))
+ << "Should return value provided by mapper when device id is valid and the device "
+ "supports some of the sources.";
ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(-1,
AINPUT_SOURCE_TRACKBALL, SW_LID))
@@ -1519,8 +1549,11 @@
}
TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+ constexpr int32_t eventHubId = 1;
FakeInputMapper& mapper =
- addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD,
+ addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
AINPUT_SOURCE_KEYBOARD, nullptr);
mapper.addSupportedKeyCode(AKEYCODE_A);
@@ -1534,13 +1567,16 @@
ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]);
flags[3] = 1;
- ASSERT_FALSE(mReader->hasKeys(1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
- << "Should return false when device id is valid but the sources are not supported by the device.";
+ ASSERT_FALSE(mReader->hasKeys(deviceId, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
+ << "Should return false when device id is valid but the sources are not supported by "
+ "the device.";
ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]);
flags[3] = 1;
- ASSERT_TRUE(mReader->hasKeys(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags))
- << "Should return value provided by mapper when device id is valid and the device supports some of the sources.";
+ ASSERT_TRUE(mReader->hasKeys(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4,
+ keyCodes, flags))
+ << "Should return value provided by mapper when device id is valid and the device "
+ "supports some of the sources.";
ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]);
flags[3] = 1;
@@ -1555,7 +1591,8 @@
}
TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) {
- addDevice(1, "ignored", INPUT_DEVICE_CLASS_KEYBOARD, nullptr);
+ constexpr int32_t eventHubId = 1;
+ addDevice(eventHubId, "ignored", INPUT_DEVICE_CLASS_KEYBOARD, nullptr);
NotifyConfigurationChangedArgs args;
@@ -1564,31 +1601,35 @@
}
TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+ constexpr int32_t eventHubId = 1;
FakeInputMapper& mapper =
- addDeviceWithFakeInputMapper(1, 0, "fake", INPUT_DEVICE_CLASS_KEYBOARD,
+ addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass,
AINPUT_SOURCE_KEYBOARD, nullptr);
- mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1);
+ mFakeEventHub->enqueueEvent(0, eventHubId, EV_KEY, KEY_A, 1);
mReader->loopOnce();
ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty());
RawEvent event;
ASSERT_NO_FATAL_FAILURE(mapper.assertProcessWasCalled(&event));
ASSERT_EQ(0, event.when);
- ASSERT_EQ(1, event.deviceId);
+ ASSERT_EQ(eventHubId, event.deviceId);
ASSERT_EQ(EV_KEY, event.type);
ASSERT_EQ(KEY_A, event.code);
ASSERT_EQ(1, event.value);
}
TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) {
- constexpr int32_t deviceId = 1;
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
+ constexpr int32_t eventHubId = 1;
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
// Must add at least one mapper or the device will be ignored!
- device->addMapper<FakeInputMapper>(AINPUT_SOURCE_KEYBOARD);
+ device->addMapper<FakeInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
mReader->setNextDevice(device);
- ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
NotifyDeviceResetArgs resetArgs;
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
@@ -1614,12 +1655,13 @@
}
TEST_F(InputReaderTest, Device_CanDispatchToDisplay) {
- constexpr int32_t deviceId = 1;
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+ constexpr int32_t eventHubId = 1;
const char* DEVICE_LOCATION = "USB1";
- InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass,
- DEVICE_LOCATION);
- FakeInputMapper& mapper = device->addMapper<FakeInputMapper>(AINPUT_SOURCE_TOUCHSCREEN);
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
+ FakeInputMapper& mapper =
+ device->addMapper<FakeInputMapper>(eventHubId, AINPUT_SOURCE_TOUCHSCREEN);
mReader->setNextDevice(device);
const uint8_t hdmi1 = 1;
@@ -1639,7 +1681,7 @@
// Add the device, and make sure all of the callbacks are triggered.
// The device is added after the input port associations are processed since
// we do not yet support dynamic device-to-display associations.
- ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr));
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled());
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled());
@@ -1655,6 +1697,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 = new InputReader(std::make_shared<EventHub>(), 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 {
@@ -1665,13 +1820,14 @@
static const int32_t DEVICE_GENERATION;
static const int32_t DEVICE_CONTROLLER_NUMBER;
static const uint32_t DEVICE_CLASSES;
+ static const int32_t EVENTHUB_ID;
std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
sp<TestInputListener> mFakeListener;
FakeInputReaderContext* mFakeContext;
- InputDevice* mDevice;
+ std::shared_ptr<InputDevice> mDevice;
virtual void SetUp() override {
mFakeEventHub = std::make_unique<FakeEventHub>();
@@ -1679,17 +1835,16 @@
mFakeListener = new TestInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
- mFakeEventHub->addDevice(DEVICE_ID, DEVICE_NAME, 0);
+ mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, 0);
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,
+ identifier);
}
virtual void TearDown() override {
- delete mDevice;
-
+ mDevice = nullptr;
delete mFakeContext;
mFakeListener.clear();
mFakePolicy.clear();
@@ -1698,20 +1853,21 @@
const char* InputDeviceTest::DEVICE_NAME = "device";
const char* InputDeviceTest::DEVICE_LOCATION = "USB1";
-const int32_t InputDeviceTest::DEVICE_ID = 1;
+const int32_t InputDeviceTest::DEVICE_ID = END_RESERVED_ID + 1000;
const int32_t InputDeviceTest::DEVICE_GENERATION = 2;
const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0;
const uint32_t InputDeviceTest::DEVICE_CLASSES = INPUT_DEVICE_CLASS_KEYBOARD
| INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_JOYSTICK;
+const int32_t InputDeviceTest::EVENTHUB_ID = 1;
TEST_F(InputDeviceTest, ImmutableProperties) {
ASSERT_EQ(DEVICE_ID, mDevice->getId());
ASSERT_STREQ(DEVICE_NAME, mDevice->getName().c_str());
- ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses());
+ ASSERT_EQ(0U, mDevice->getClasses());
}
-TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsTrue) {
- ASSERT_EQ(mDevice->isEnabled(), true);
+TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsFalse) {
+ ASSERT_EQ(mDevice->isEnabled(), false);
}
TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) {
@@ -1758,9 +1914,10 @@
TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) {
// Configuration.
- mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value"));
+ mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, String8("key"), String8("value"));
- FakeInputMapper& mapper1 = mDevice->addMapper<FakeInputMapper>(AINPUT_SOURCE_KEYBOARD);
+ FakeInputMapper& mapper1 =
+ mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
mapper1.setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC);
mapper1.setMetaState(AMETA_ALT_ON);
mapper1.addSupportedKeyCode(AKEYCODE_A);
@@ -1771,7 +1928,8 @@
mapper1.setScanCodeState(3, AKEY_STATE_UP);
mapper1.setSwitchState(4, AKEY_STATE_DOWN);
- FakeInputMapper& mapper2 = mDevice->addMapper<FakeInputMapper>(AINPUT_SOURCE_TOUCHSCREEN);
+ FakeInputMapper& mapper2 =
+ mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_TOUCHSCREEN);
mapper2.setMetaState(AMETA_SHIFT_ON);
InputReaderConfiguration config;
@@ -1842,6 +2000,7 @@
// Event handling.
RawEvent event;
+ event.deviceId = EVENTHUB_ID;
mDevice->process(&event, 1);
ASSERT_NO_FATAL_FAILURE(mapper1.assertProcessWasCalled());
@@ -1852,7 +2011,7 @@
// 1. Device is disabled if the viewport corresponding to the associated display is not found
// 2. Device is disabled when setEnabled API is called
TEST_F(InputDeviceTest, Configure_AssignsDisplayPort) {
- mDevice->addMapper<FakeInputMapper>(AINPUT_SOURCE_TOUCHSCREEN);
+ mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_TOUCHSCREEN);
// First Configuration.
mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
@@ -1901,6 +2060,7 @@
static const int32_t DEVICE_GENERATION;
static const int32_t DEVICE_CONTROLLER_NUMBER;
static const uint32_t DEVICE_CLASSES;
+ static const int32_t EVENTHUB_ID;
std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
@@ -1908,7 +2068,7 @@
FakeInputReaderContext* mFakeContext;
InputDevice* mDevice;
- virtual void SetUp() override {
+ virtual void SetUp(uint32_t classes) {
mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new TestInputListener();
@@ -1916,12 +2076,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 = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, identifier);
- mFakeEventHub->addDevice(mDevice->getId(), DEVICE_NAME, 0);
+ mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, classes);
}
+ virtual void SetUp() override { SetUp(DEVICE_CLASSES); }
+
virtual void TearDown() override {
delete mDevice;
delete mFakeContext;
@@ -1930,7 +2091,7 @@
}
void addConfigurationProperty(const char* key, const char* value) {
- mFakeEventHub->addConfigurationProperty(mDevice->getId(), String8(key), String8(value));
+ mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, String8(key), String8(value));
}
void configureDevice(uint32_t changes) {
@@ -1939,7 +2100,7 @@
template <class T, typename... Args>
T& addMapperAndConfigure(Args... args) {
- T& mapper = mDevice->addMapper<T>(args...);
+ T& mapper = mDevice->addMapper<T>(EVENTHUB_ID, args...);
configureDevice(0);
mDevice->reset(ARBITRARY_TIME);
return mapper;
@@ -1961,7 +2122,7 @@
int32_t value) {
RawEvent event;
event.when = when;
- event.deviceId = mapper.getDeviceId();
+ event.deviceId = mapper.getDeviceContext().getEventHubId();
event.type = type;
event.code = code;
event.value = value;
@@ -2006,11 +2167,11 @@
const char* InputMapperTest::DEVICE_NAME = "device";
const char* InputMapperTest::DEVICE_LOCATION = "USB1";
-const int32_t InputMapperTest::DEVICE_ID = 1;
+const int32_t InputMapperTest::DEVICE_ID = END_RESERVED_ID + 1000;
const int32_t InputMapperTest::DEVICE_GENERATION = 2;
const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0;
const uint32_t InputMapperTest::DEVICE_CLASSES = 0; // not needed for current tests
-
+const int32_t InputMapperTest::EVENTHUB_ID = 1;
// --- SwitchInputMapperTest ---
@@ -2027,10 +2188,10 @@
TEST_F(SwitchInputMapperTest, GetSwitchState) {
SwitchInputMapper& mapper = addMapperAndConfigure<SwitchInputMapper>();
- mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 1);
+ mFakeEventHub->setSwitchState(EVENTHUB_ID, SW_LID, 1);
ASSERT_EQ(1, mapper.getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
- mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 0);
+ mFakeEventHub->setSwitchState(EVENTHUB_ID, SW_LID, 0);
ASSERT_EQ(0, mapper.getSwitchState(AINPUT_SOURCE_ANY, SW_LID));
}
@@ -2104,8 +2265,8 @@
TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) {
const int32_t USAGE_A = 0x070004;
const int32_t USAGE_UNKNOWN = 0x07ffff;
- mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
- mFakeEventHub->addKey(DEVICE_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
+ mFakeEventHub->addKey(EVENTHUB_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);
KeyboardInputMapper& mapper =
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
@@ -2202,8 +2363,8 @@
}
TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) {
- mFakeEventHub->addKey(DEVICE_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
KeyboardInputMapper& mapper =
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
@@ -2241,10 +2402,10 @@
}
TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) {
- mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
KeyboardInputMapper& mapper =
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
@@ -2262,10 +2423,10 @@
}
TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
- mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
addConfigurationProperty("keyboard.orientationAware", "1");
KeyboardInputMapper& mapper =
@@ -2338,7 +2499,7 @@
TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_NotOrientationAware) {
// If the keyboard is not orientation aware,
// key events should not be associated with a specific display id
- mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
KeyboardInputMapper& mapper =
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
@@ -2363,7 +2524,7 @@
TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) {
// If the keyboard is orientation aware,
// key events should be associated with the internal viewport
- mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
addConfigurationProperty("keyboard.orientationAware", "1");
KeyboardInputMapper& mapper =
@@ -2398,10 +2559,10 @@
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 1);
+ mFakeEventHub->setKeyCodeState(EVENTHUB_ID, AKEYCODE_A, 1);
ASSERT_EQ(1, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
- mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 0);
+ mFakeEventHub->setKeyCodeState(EVENTHUB_ID, AKEYCODE_A, 0);
ASSERT_EQ(0, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A));
}
@@ -2410,10 +2571,10 @@
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 1);
+ mFakeEventHub->setScanCodeState(EVENTHUB_ID, KEY_A, 1);
ASSERT_EQ(1, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
- mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 0);
+ mFakeEventHub->setScanCodeState(EVENTHUB_ID, KEY_A, 0);
ASSERT_EQ(0, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A));
}
@@ -2422,7 +2583,7 @@
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
- mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B };
uint8_t flags[2] = { 0, 0 };
@@ -2432,99 +2593,100 @@
}
TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) {
- mFakeEventHub->addLed(DEVICE_ID, LED_CAPSL, true /*initially on*/);
- mFakeEventHub->addLed(DEVICE_ID, LED_NUML, false /*initially off*/);
- mFakeEventHub->addLed(DEVICE_ID, LED_SCROLLL, false /*initially off*/);
- mFakeEventHub->addKey(DEVICE_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_CAPSL, true /*initially on*/);
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_NUML, false /*initially off*/);
+ mFakeEventHub->addLed(EVENTHUB_ID, LED_SCROLLL, false /*initially off*/);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
KeyboardInputMapper& mapper =
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
// Initialization should have turned all of the lights off.
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
// Toggle caps lock on.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 1);
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 0);
- ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
// Toggle num lock on.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 1);
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 0);
- ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
- ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper.getMetaState());
// Toggle caps lock off.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 1);
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 0);
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
- ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
// Toggle scroll lock on.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
- ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
- ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
// Toggle num lock off.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 1);
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 0);
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
- ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
// Toggle scroll lock off.
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL));
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML));
- ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
+ ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
}
TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) {
// keyboard 1.
- mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
// keyboard 2.
const std::string USB2 = "USB2";
constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
+ constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
InputDeviceIdentifier identifier;
identifier.name = "KEYBOARD2";
identifier.location = USB2;
std::unique_ptr<InputDevice> device2 =
std::make_unique<InputDevice>(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION,
- DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
- mFakeEventHub->addDevice(SECOND_DEVICE_ID, DEVICE_NAME, 0 /*classes*/);
- mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
- mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
- mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
- mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
+ identifier);
+ mFakeEventHub->addDevice(SECOND_EVENTHUB_ID, DEVICE_NAME, 0 /*classes*/);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+ mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
KeyboardInputMapper& mapper =
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
KeyboardInputMapper& mapper2 =
- device2->addMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ device2->addMapper<KeyboardInputMapper>(SECOND_EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD,
AINPUT_KEYBOARD_TYPE_ALPHABETIC);
device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
device2->reset(ARBITRARY_TIME);
@@ -2576,14 +2738,23 @@
AKEYCODE_DPAD_LEFT, newDisplayId));
}
-TEST_F(KeyboardInputMapperTest, ExternalDevice_WakeBehavior) {
+// --- KeyboardInputMapperTest_ExternalDevice ---
+
+class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest {
+protected:
+ virtual void SetUp() override {
+ InputMapperTest::SetUp(DEVICE_CLASSES | INPUT_DEVICE_CLASS_EXTERNAL);
+ }
+};
+
+TEST_F(KeyboardInputMapperTest_ExternalDevice, WakeBehavior) {
// For external devices, non-media keys will trigger wake on key down. Media keys need to be
// marked as WAKE in the keylayout file to trigger wake.
- mDevice->setExternal(true);
- mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE, POLICY_FLAG_WAKE);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAYPAUSE, 0, AKEYCODE_MEDIA_PLAY_PAUSE,
+ POLICY_FLAG_WAKE);
KeyboardInputMapper& mapper =
addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
@@ -2615,13 +2786,12 @@
ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags);
}
-TEST_F(KeyboardInputMapperTest, ExternalDevice_DoNotWakeByDefaultBehavior) {
+TEST_F(KeyboardInputMapperTest_ExternalDevice, DoNotWakeByDefaultBehavior) {
// Tv Remote key's wake behavior is prescribed by the keylayout file.
- mDevice->setExternal(true);
- mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
- mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
- mFakeEventHub->addKey(DEVICE_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, POLICY_FLAG_WAKE);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_PLAY, 0, AKEYCODE_MEDIA_PLAY, POLICY_FLAG_WAKE);
addConfigurationProperty("keyboard.doNotWakeByDefault", "1");
KeyboardInputMapper& mapper =
@@ -3563,10 +3733,10 @@
}
void TouchInputMapperTest::prepareVirtualKeys() {
- mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]);
- mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]);
- mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
- mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, 0, AKEYCODE_MENU, POLICY_FLAG_WAKE);
+ mFakeEventHub->addVirtualKeyDefinition(EVENTHUB_ID, VIRTUAL_KEYS[0]);
+ mFakeEventHub->addVirtualKeyDefinition(EVENTHUB_ID, VIRTUAL_KEYS[1]);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_MENU, 0, AKEYCODE_MENU, POLICY_FLAG_WAKE);
}
void TouchInputMapperTest::prepareLocationCalibration() {
@@ -3627,33 +3797,29 @@
};
void SingleTouchInputMapperTest::prepareButtons() {
- mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
}
void SingleTouchInputMapperTest::prepareAxes(int axes) {
if (axes & POSITION) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_X,
- RAW_X_MIN, RAW_X_MAX, 0, 0);
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_Y,
- RAW_Y_MIN, RAW_Y_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
}
if (axes & PRESSURE) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_PRESSURE,
- RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_PRESSURE, RAW_PRESSURE_MIN,
+ RAW_PRESSURE_MAX, 0, 0);
}
if (axes & TOOL) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TOOL_WIDTH,
- RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_TOOL_WIDTH, RAW_TOOL_MIN, RAW_TOOL_MAX, 0,
+ 0);
}
if (axes & DISTANCE) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_DISTANCE,
- RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_DISTANCE, RAW_DISTANCE_MIN,
+ RAW_DISTANCE_MAX, 0, 0);
}
if (axes & TILT) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_X,
- RAW_TILT_MIN, RAW_TILT_MAX, 0, 0);
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_Y,
- RAW_TILT_MIN, RAW_TILT_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_TILT_X, RAW_TILT_MIN, RAW_TILT_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_TILT_Y, RAW_TILT_MIN, RAW_TILT_MAX, 0, 0);
}
}
@@ -3709,8 +3875,8 @@
}
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) {
- mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X);
- mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y);
+ mFakeEventHub->addRelativeAxis(EVENTHUB_ID, REL_X);
+ mFakeEventHub->addRelativeAxis(EVENTHUB_ID, REL_Y);
prepareButtons();
prepareAxes(POSITION);
SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
@@ -4777,7 +4943,7 @@
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareButtons();
prepareAxes(POSITION);
- mFakeEventHub->addKey(DEVICE_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0);
SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
NotifyMotionArgs motionArgs;
@@ -4939,51 +5105,47 @@
void MultiTouchInputMapperTest::prepareAxes(int axes) {
if (axes & POSITION) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_X,
- RAW_X_MIN, RAW_X_MAX, 0, 0);
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_Y,
- RAW_Y_MIN, RAW_Y_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
}
if (axes & TOUCH) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR,
- RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN,
+ RAW_TOUCH_MAX, 0, 0);
if (axes & MINOR) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR,
- RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, RAW_TOUCH_MIN,
+ RAW_TOUCH_MAX, 0, 0);
}
}
if (axes & TOOL) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR,
- RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX,
+ 0, 0);
if (axes & MINOR) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR,
- RAW_TOOL_MAX, RAW_TOOL_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MAX,
+ RAW_TOOL_MAX, 0, 0);
}
}
if (axes & ORIENTATION) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_ORIENTATION,
- RAW_ORIENTATION_MIN, RAW_ORIENTATION_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_ORIENTATION, RAW_ORIENTATION_MIN,
+ RAW_ORIENTATION_MAX, 0, 0);
}
if (axes & PRESSURE) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_PRESSURE,
- RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_PRESSURE, RAW_PRESSURE_MIN,
+ RAW_PRESSURE_MAX, 0, 0);
}
if (axes & DISTANCE) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_DISTANCE,
- RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_DISTANCE, RAW_DISTANCE_MIN,
+ RAW_DISTANCE_MAX, 0, 0);
}
if (axes & ID) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TRACKING_ID,
- RAW_ID_MIN, RAW_ID_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TRACKING_ID, RAW_ID_MIN, RAW_ID_MAX, 0,
+ 0);
}
if (axes & SLOT) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_SLOT,
- RAW_SLOT_MIN, RAW_SLOT_MAX, 0, 0);
- mFakeEventHub->setAbsoluteAxisValue(DEVICE_ID, ABS_MT_SLOT, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_SLOT, RAW_SLOT_MIN, RAW_SLOT_MAX, 0, 0);
+ mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT, 0);
}
if (axes & TOOL_TYPE) {
- mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOOL_TYPE,
- 0, MT_TOOL_MAX, 0, 0);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0);
}
}
@@ -6272,7 +6434,7 @@
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT);
- mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
NotifyMotionArgs motionArgs;
@@ -6451,35 +6613,6 @@
ASSERT_EQ(DISPLAY_ID, args.displayId);
}
-/**
- * Expect fallback to internal viewport if device is external and external viewport is not present.
- */
-TEST_F(MultiTouchInputMapperTest, Viewports_Fallback) {
- prepareAxes(POSITION);
- addConfigurationProperty("touch.deviceType", "touchScreen");
- prepareDisplay(DISPLAY_ORIENTATION_0);
- mDevice->setExternal(true);
- MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
-
- ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources());
-
- NotifyMotionArgs motionArgs;
-
- // Expect the event to be sent to the internal viewport,
- // because an external viewport is not present.
- processPosition(mapper, 100, 100);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(ADISPLAY_ID_DEFAULT, motionArgs.displayId);
-
- // Expect the event to be sent to the external viewport if it is present.
- prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL);
- processPosition(mapper, 100, 100);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
-}
-
TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) {
// Setup for second display.
sp<FakePointerController> fakePointerController = new FakePointerController();
@@ -6516,27 +6649,28 @@
// Create the second touch screen device, and enable multi fingers.
const std::string USB2 = "USB2";
constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
+ constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
InputDeviceIdentifier identifier;
identifier.name = "TOUCHSCREEN2";
identifier.location = USB2;
std::unique_ptr<InputDevice> device2 =
std::make_unique<InputDevice>(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION,
- DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
- mFakeEventHub->addDevice(SECOND_DEVICE_ID, DEVICE_NAME, 0 /*classes*/);
- mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX,
- 0 /*flat*/, 0 /*fuzz*/);
- mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX,
- 0 /*flat*/, 0 /*fuzz*/);
- mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_TRACKING_ID, RAW_ID_MIN, RAW_ID_MAX,
- 0 /*flat*/, 0 /*fuzz*/);
- mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_SLOT, RAW_SLOT_MIN, RAW_SLOT_MAX,
- 0 /*flat*/, 0 /*fuzz*/);
- mFakeEventHub->setAbsoluteAxisValue(SECOND_DEVICE_ID, ABS_MT_SLOT, 0 /*value*/);
- mFakeEventHub->addConfigurationProperty(SECOND_DEVICE_ID, String8("touch.deviceType"),
- String8("touchScreen"));
+ identifier);
+ mFakeEventHub->addDevice(SECOND_EVENTHUB_ID, DEVICE_NAME, 0 /*classes*/);
+ mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX,
+ 0 /*flat*/, 0 /*fuzz*/);
+ mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX,
+ 0 /*flat*/, 0 /*fuzz*/);
+ mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_TRACKING_ID, RAW_ID_MIN, RAW_ID_MAX,
+ 0 /*flat*/, 0 /*fuzz*/);
+ mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_SLOT, RAW_SLOT_MIN, RAW_SLOT_MAX,
+ 0 /*flat*/, 0 /*fuzz*/);
+ mFakeEventHub->setAbsoluteAxisValue(SECOND_EVENTHUB_ID, ABS_MT_SLOT, 0 /*value*/);
+ mFakeEventHub->addConfigurationProperty(SECOND_EVENTHUB_ID, String8("touch.deviceType"),
+ String8("touchScreen"));
// Setup the second touch screen device.
- MultiTouchInputMapper& mapper2 = device2->addMapper<MultiTouchInputMapper>();
+ MultiTouchInputMapper& mapper2 = device2->addMapper<MultiTouchInputMapper>(SECOND_EVENTHUB_ID);
device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
device2->reset(ARBITRARY_TIME);
@@ -6597,7 +6731,7 @@
// Unrotated video frame
TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
std::vector<TouchVideoFrame> frames{frame};
- mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}});
+ mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}});
processPosition(mapper, 100, 200);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -6627,7 +6761,7 @@
clearViewports();
prepareDisplay(orientation);
std::vector<TouchVideoFrame> frames{frame};
- mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}});
+ mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}});
processPosition(mapper, 100, 200);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -6649,7 +6783,7 @@
NotifyMotionArgs motionArgs;
prepareDisplay(DISPLAY_ORIENTATION_90);
- mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}});
+ mFakeEventHub->setVideoFrames({{EVENTHUB_ID, frames}});
processPosition(mapper, 100, 200);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -6823,4 +6957,41 @@
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
}
+// --- MultiTouchInputMapperTest_ExternalDevice ---
+
+class MultiTouchInputMapperTest_ExternalDevice : public MultiTouchInputMapperTest {
+protected:
+ virtual void SetUp() override {
+ InputMapperTest::SetUp(DEVICE_CLASSES | INPUT_DEVICE_CLASS_EXTERNAL);
+ }
+};
+
+/**
+ * Expect fallback to internal viewport if device is external and external viewport is not present.
+ */
+TEST_F(MultiTouchInputMapperTest_ExternalDevice, Viewports_Fallback) {
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources());
+
+ NotifyMotionArgs motionArgs;
+
+ // Expect the event to be sent to the internal viewport,
+ // because an external viewport is not present.
+ processPosition(mapper, 100, 100);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(ADISPLAY_ID_DEFAULT, motionArgs.displayId);
+
+ // Expect the event to be sent to the external viewport if it is present.
+ prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL);
+ processPosition(mapper, 100, 100);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
+}
+
} // namespace android
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 78c9ab1..729d075 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>
@@ -800,6 +803,7 @@
}
info->secure = display->isSecure();
+ info->deviceProductInfo = getDeviceProductInfoLocked(*display);
return NO_ERROR;
}
@@ -1274,6 +1278,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,
@@ -3577,9 +3605,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
@@ -4677,6 +4709,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;
@@ -5890,6 +5925,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 cdf1c89..c79621b 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();