正常情况下,无论是 Awinic Haptics 还是 QTI Haptics 其实 HAL 实现代码都大同小异,甚至后者的代码可以给前者使用,但是在部分情况下,会表现出缺少震动效果的问题,例如部分类原生 ROM 的亮度条震动和所有类原生 ROM 的后台卡片震动,因为这部分使用的震动效果是 TICK,而 HAL 无法正确响应 TICK 操作将数值写入到没核节点中,从而导致震动失效。
对此,我们需要通过修改 HAL 的源码来实现这些操作,以下操作将以联想拯救者Y70进行操作
前提条件
- 手机需要 Root
- ADB
- 确保官方 ROM 有 strace 命令(没有也没关系,你都有 root 了我想你也知道怎么做)
- VibeTest
读取官方 ROM 相关效果写入内核的值
首先 ADB 连接手机并授予adb shell权限
确定 vibrator 服务相关的 PID,例如现在 拯救者 Y70 手机的震动服务为 114514
然后我们使用 strace 来跟踪 vibrator 服务的一些操作
strace -fp 114515 -e openat,write
然后打开 VibeTest 软件,依次点击以下特效并记录 strace 输出的日志
CLICK,DOUBLE_CLICK,TICK,THUD,POP,HEAVY_CLICK
分析日志
这里我们使用CLICK效果来说明
日志输出为下文
openat(AT_FDCWD, "/sys/class/leds/vibrator/state", O_WRONLY) = 8
write(8, "1\0", 2) = 2
openat(AT_FDCWD, "/sys/class/leds/vibrator/duration", O_WRONLY) = 8
write(8, "60\n\0", 4) = 4
openat(AT_FDCWD, "/sys/class/leds/vibrator/activate", O_WRONLY) = 8
write(8, "1\0", 2) = 2
strace: Process 10208 attached
[pid 1196] openat(AT_FDCWD, "/sys/class/leds/vibrator/activate", O_WRONLY) = 8
[pid 10208] +++ exited with 0 +++
write(8, "0\0", 2) = 2
说明官方震动 HAL 对以下内核节点写入了下列值
内核节点 | 值 |
---|---|
/sys/class/leds/vibrator/state | 1 |
/sys/class/leds/vibrator/duration | 60 |
/sys/class/leds/vibrator/activate | 1 |
修改 HAL 代码
Vibrator.cpp
创建map来记录相关内核节点和值,代码如下(这里用CLICK举例)
static std::map<Effect, std::vector<std::pair<std::string, std::string>>> LED_EFFECTS{
{ Effect::CLICK, {
{ "/sys/class/leds/vibrator/state", "1" },
{ "/sys/class/leds/vibrator/duration", "60" },
{ "/sys/class/leds/vibrator/activate", "1" },
}}
};
修改ndk::ScopedAStatus Vibrator::perform
方法
修改下列代码
if (ledVib.mDetected)
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
(effect < Effect::CLICK ||
effect > Effect::HEAVY_CLICK)
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
if (es != EffectStrength::LIGHT && es != EffectStrength::MEDIUM && es != EffectStrength::STRONG)
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
ret = ff.playEffect((static_cast<int>(effect)), es, &playLengthMs);
if (ret != 0)
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));
为
if (ledVib.mDetected) {
if (const auto it = LED_EFFECTS.find(effect); it != LED_EFFECTS.end()) {
for (const auto &[path, value] : it->second) {
if (path == "SLEEP") {
usleep(atoi(value.c_str()) * 1000);
} else {
ledVib.write_value(path.c_str(), value.c_str());
}
}
playLengthMs = 150;
} else {
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
}
} else {
if (effect < Effect::CLICK ||
effect > Effect::HEAVY_CLICK)
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
if (es != EffectStrength::LIGHT && es != EffectStrength::MEDIUM && es != EffectStrength::STRONG)
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
ret = ff.playEffect((static_cast<int>(effect)), es, &playLengthMs);
if (ret != 0)
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_SERVICE_SPECIFIC));
}
修改ndk::ScopedAStatus Vibrator::getSupportedEffects
方法
将下列代码
if (ledVib.mDetected)
return ndk::ScopedAStatus::ok();
修改为
if (ledVib.mDetected)
*_aidl_return = {Effect::你要支持的效果};
Vibrator.h
公开write_value方法
将int write_value(const char *file, const char *value);
上的private:
拿掉即可
评论 (0)