Bruno Martins e41ad9878e sm6250-common: power-libperfmgr: Scan input devices for eligible DT2W node
It is no longer a surprise for anyone to see Xiaomi shipping the same
device with different displays and different displays usually mean
different touchscreen drivers.

The current double tap handling in the power HAL only takes into
account one specific node, meant to be set in the device tree.
However, if the touchscreen was registered as a different input device
it would cause the feature to be broken. Address the issue by iterating
through the input devices in order to find one supported touchscreen
input to be used.

Co-authored-by: LuK1337 <priv.luk@gmail.com>
Change-Id: I2f7fb4a8b0c9cd1a16d6c2b93602d285a191f170
2020-08-31 11:14:31 +03:00

279 lines
9.1 KiB
C++

/*
* 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.
*/
#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
#define LOG_TAG "android.hardware.power@1.3-service.xiaomi_sm6250-libperfmgr"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <mutex>
#include <utils/Log.h>
#include <utils/Trace.h>
#include "Power.h"
#include <linux/input.h>
constexpr int kWakeupModeOff = 4;
constexpr int kWakeupModeOn = 5;
namespace android {
namespace hardware {
namespace power {
namespace V1_3 {
namespace implementation {
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::power::V1_0::Feature;
using ::android::hardware::power::V1_0::Status;
constexpr char kPowerHalStateProp[] = "vendor.powerhal.state";
constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio";
constexpr char kPowerHalInitProp[] = "vendor.powerhal.init";
constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering";
constexpr char kPowerHalConfigPath[] = "/vendor/etc/powerhint.json";
Power::Power()
: mHintManager(nullptr),
mInteractionHandler(nullptr),
mSustainedPerfModeOn(false),
mReady(false) {
mInitThread = std::thread([this]() {
android::base::WaitForProperty(kPowerHalInitProp, "1");
mHintManager = HintManager::GetFromJSON(kPowerHalConfigPath);
if (!mHintManager) {
LOG(FATAL) << "Invalid config: " << kPowerHalConfigPath;
}
mInteractionHandler = std::make_unique<InteractionHandler>(mHintManager);
mInteractionHandler->Init();
std::string state = android::base::GetProperty(kPowerHalStateProp, "");
if (state == "SUSTAINED_PERFORMANCE") {
ALOGI("Initialize with SUSTAINED_PERFORMANCE on");
mHintManager->DoHint("SUSTAINED_PERFORMANCE");
mSustainedPerfModeOn = true;
} else {
ALOGI("Initialize PowerHAL");
}
state = android::base::GetProperty(kPowerHalAudioProp, "");
if (state == "AUDIO_LOW_LATENCY") {
ALOGI("Initialize with AUDIO_LOW_LATENCY on");
mHintManager->DoHint("AUDIO_LOW_LATENCY");
}
state = android::base::GetProperty(kPowerHalRenderingProp, "");
if (state == "EXPENSIVE_RENDERING") {
ALOGI("Initialize with EXPENSIVE_RENDERING on");
mHintManager->DoHint("EXPENSIVE_RENDERING");
}
// Now start to take powerhint
mReady.store(true);
ALOGI("PowerHAL ready to process hints");
});
mInitThread.detach();
}
// Methods from ::android::hardware::power::V1_0::IPower follow.
Return<void> Power::setInteractive(bool /* interactive */) {
return Void();
}
Return<void> Power::powerHint(PowerHint_1_0 hint, int32_t data) {
if (!mReady) {
return Void();
}
ATRACE_INT(android::hardware::power::V1_0::toString(hint).c_str(), data);
ALOGD_IF(hint != PowerHint_1_0::INTERACTION, "%s: %d",
android::hardware::power::V1_0::toString(hint).c_str(), static_cast<int>(data));
switch (hint) {
case PowerHint_1_0::INTERACTION:
if (mSustainedPerfModeOn) {
ALOGV("%s: ignoring due to other active perf hints", __func__);
} else {
mInteractionHandler->Acquire(data);
}
break;
case PowerHint_1_0::SUSTAINED_PERFORMANCE:
if (data && !mSustainedPerfModeOn) {
mHintManager->DoHint("SUSTAINED_PERFORMANCE");
mSustainedPerfModeOn = true;
} else if (!data && mSustainedPerfModeOn) {
mHintManager->EndHint("SUSTAINED_PERFORMANCE");
mSustainedPerfModeOn = false;
}
break;
case PowerHint_1_0::LAUNCH:
if (mSustainedPerfModeOn) {
ALOGV("%s: ignoring due to other active perf hints", __func__);
} else {
if (data) {
// Hint until canceled
mHintManager->DoHint("LAUNCH");
} else {
mHintManager->EndHint("LAUNCH");
}
}
break;
case PowerHint_1_0::LOW_POWER:
break;
default:
break;
}
return Void();
}
int open_ts_input() {
int fd = -1;
DIR *dir = opendir("/dev/input");
if (dir != NULL) {
struct dirent *ent;
while ((ent = readdir(dir)) != NULL) {
if (ent->d_type == DT_CHR) {
char absolute_path[PATH_MAX] = {0};
char name[80] = {0};
strcpy(absolute_path, "/dev/input/");
strcat(absolute_path, ent->d_name);
fd = open(absolute_path, O_RDWR);
if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) > 0) {
if (strcmp(name, "fts_ts") == 0 ||
strcmp(name, "NVTCapacitiveTouchScreen") == 0)
break;
}
close(fd);
fd = -1;
}
}
closedir(dir);
}
return fd;
}
Return<void> Power::setFeature(Feature feature, bool activate) {
switch (feature) {
case Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE: {
int fd = open_ts_input();
if (fd == -1) {
ALOGW("DT2W won't work because no supported touchscreen input devices were found");
return Void();
}
struct input_event ev;
ev.type = EV_SYN;
ev.code = SYN_CONFIG;
ev.value = activate ? kWakeupModeOn : kWakeupModeOff;
write(fd, &ev, sizeof(ev));
close(fd);
} break;
default:
break;
}
return Void();
}
Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) {
LOG(ERROR) << "getPlatformLowPowerStats not supported. Use IPowerStats HAL.";
_hidl_cb({}, Status::SUCCESS);
return Void();
}
// Methods from ::android::hardware::power::V1_1::IPower follow.
Return<void> Power::getSubsystemLowPowerStats(getSubsystemLowPowerStats_cb _hidl_cb) {
LOG(ERROR) << "getSubsystemLowPowerStats not supported. Use IPowerStats HAL.";
_hidl_cb({}, Status::SUCCESS);
return Void();
}
Return<void> Power::powerHintAsync(PowerHint_1_0 hint, int32_t data) {
// just call the normal power hint in this oneway function
return powerHint(hint, data);
}
// Methods from ::android::hardware::power::V1_2::IPower follow.
Return<void> Power::powerHintAsync_1_2(PowerHint_1_2 hint, int32_t data) {
if (!mReady) {
return Void();
}
ATRACE_INT(android::hardware::power::V1_2::toString(hint).c_str(), data);
ALOGD_IF(hint >= PowerHint_1_2::AUDIO_STREAMING, "%s: %d",
android::hardware::power::V1_2::toString(hint).c_str(), static_cast<int>(data));
switch (hint) {
case PowerHint_1_2::AUDIO_LOW_LATENCY:
if (data) {
// Hint until canceled
mHintManager->DoHint("AUDIO_LOW_LATENCY");
} else {
mHintManager->EndHint("AUDIO_LOW_LATENCY");
}
break;
case PowerHint_1_2::AUDIO_STREAMING:
if (mSustainedPerfModeOn) {
ALOGV("%s: ignoring due to other active perf hints", __func__);
} else {
if (data) {
mHintManager->DoHint("AUDIO_STREAMING");
} else {
mHintManager->EndHint("AUDIO_STREAMING");
}
}
break;
default:
return powerHint(static_cast<PowerHint_1_0>(hint), data);
}
return Void();
}
// Methods from ::android::hardware::power::V1_3::IPower follow.
Return<void> Power::powerHintAsync_1_3(PowerHint_1_3 hint, int32_t data) {
if (!mReady) {
return Void();
}
if (hint == PowerHint_1_3::EXPENSIVE_RENDERING) {
ATRACE_INT(android::hardware::power::V1_3::toString(hint).c_str(), data);
if (mSustainedPerfModeOn) {
ALOGV("%s: ignoring due to other active perf hints", __func__);
} else {
if (data > 0) {
mHintManager->DoHint("EXPENSIVE_RENDERING");
} else {
mHintManager->EndHint("EXPENSIVE_RENDERING");
}
}
} else {
return powerHintAsync_1_2(static_cast<PowerHint_1_2>(hint), data);
}
return Void();
}
} // namespace implementation
} // namespace V1_3
} // namespace power
} // namespace hardware
} // namespace android