背景:
前面文章已经有讲解过双击亮屏在一些方案调研情况,刚好linage os手机本身也有这个功能,刚好也有整体开源源码,所以今天带大家来对双击亮屏的源码部分进行剖析,本篇文章会一直分析到hal操作驱动节点。
设置作为切入点分析
根据字符tap to wake尝试grep相关字符在Settings这个代码中
nx563j_aosp14/packages/apps/Settings$ grep "tap_to_wake" ./ -rn
./src/com/android/settings/display/TapToWakePreferenceController.java:28: private static final String KEY_TAP_TO_WAKE = "tap_to_wake";
看看相关代码
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean value = (Boolean) newValue;
Settings.Secure.putInt(
mContext.getContentResolver(), Settings.Secure.DOUBLE_TAP_TO_WAKE, value ? 1 : 0);
return true;
}
这里PowerManagerService会监听settings值的变化然后进行设置
frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private final class SettingsObserver extends ContentObserver {
public SettingsObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
synchronized (mLock) {
handleSettingsChangedLocked();
}
}
}
具体对DOUBLE_TAP_TO_WAKE的处理
if (mSupportsDoubleTapWakeConfig) {
boolean doubleTapWakeEnabled = Settings.Secure.getIntForUser(resolver,
Settings.Secure.DOUBLE_TAP_TO_WAKE, DEFAULT_DOUBLE_TAP_TO_WAKE,
UserHandle.USER_CURRENT) != 0;
if (doubleTapWakeEnabled != mDoubleTapWakeEnabled) {
mDoubleTapWakeEnabled = doubleTapWakeEnabled;
mNativeWrapper.nativeSetPowerMode(Mode.DOUBLE_TAP_TO_WAKE, mDoubleTapWakeEnabled);
}
}
/** Wrapper for PowerManager.nativeSetPowerMode */
public boolean nativeSetPowerMode(int mode, boolean enabled) {
return PowerManagerService.nativeSetPowerMode(mode, enabled);
}
java代码就最后调用到了nativeSetPowerMode
native层面分析
frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
static jboolean nativeSetPowerMode(JNIEnv* /* env */, jclass /* clazz */, jint mode,
jboolean enabled) {
return setPowerMode(static_cast<Mode>(mode), enabled);
}
static bool setPowerMode(Mode mode, bool enabled) {
android::base::Timer t;
auto result = gPowerHalController.setMode(mode, enabled);
if (mode == Mode::INTERACTIVE && t.duration() > 20ms) {
ALOGD("Excessive delay in setting interactive mode to %s while turning screen %s",
enabled ? "true" : "false", enabled ? "on" : "off");
}
return result.isOk();
}
这里在native代码最后调用到了setPowerMode再接下来调用到PowerHalController的setMode
frameworks/native/services/powermanager/PowerHalController.cpp
HalResult<void> PowerHalController::setMode(Mode mode, bool enabled) {
std::shared_ptr<HalWrapper> handle = initHal();
auto result = handle->setMode(mode, enabled);
return processHalResult(result, "setMode");
}
这里的initHal明显可以看出其实是返回一个hal的接口来进行后面的setMode调用
std::shared_ptr<HalWrapper> PowerHalController::initHal() {
std::lock_guard<std::mutex> lock(mConnectedHalMutex);
if (mConnectedHal == nullptr) {
mConnectedHal = mHalConnector->connect();
}
return mConnectedHal;
}
这里进行了connect调用返回hal接口
std::unique_ptr<HalWrapper> HalConnector::connect() {
sp<IPower> halAidl = PowerHalLoader::loadAidl();
if (halAidl) {
return std::make_unique<AidlHalWrapper>(halAidl);
}
sp<V1_0::IPower> halHidlV1_0 = PowerHalLoader::loadHidlV1_0();
sp<V1_1::IPower> halHidlV1_1 = PowerHalLoader::loadHidlV1_1();
if (halHidlV1_1) {
return std::make_unique<HidlHalWrapperV1_1>(halHidlV1_0, halHidlV1_1);
}
if (halHidlV1_0) {
return std::make_unique<HidlHalWrapperV1_0>(halHidlV1_0);
}
return nullptr;
}
可以看出这里会依次加载aidl,hidl等接口,正常有aidl就会直接返回,没有就再加载hidl接口,这里的就需要结合具体设备上power hal的提供情况
power的aidl hal分析
我的机器设备是aidl的hal类型,hal代码是lineage os开源的,属于高通的通用一套8998代码
具体路径:
vendor/qcom/opensource/power
大家注意哈,这个hal代码路径大家自己根据情况确定,这种方式适合lineage os自带了高通开源代码
那么知道了路径后,继续分析上面提到的handle->setMode方法最后调用到了如下方法
hal实现代码路径:vendor/qcom/opensource/power/Power.cpp
ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) {
LOG(ERROR) << "Power setMode: " << static_cast<int32_t>(type) << " to: " << enabled;
#ifdef MODE_EXT
if (setDeviceSpecificMode(type, enabled)) {
return ndk::ScopedAStatus::ok();
}
#endif
switch (type) {
#ifdef TAP_TO_WAKE_NODE//可以看到这里有一个宏,而且是根据mk中变量确定编译宏
case Mode::DOUBLE_TAP_TO_WAKE:
//直接把enabled的值写入到TAP_TO_WAKE_NODE这个路径
::android::base::WriteStringToFile(enabled ? "1" : "0", TAP_TO_WAKE_NODE, true);
break;
#else
case Mode::DOUBLE_TAP_TO_WAKE:
#endif
case Mode::LOW_POWER:
case Mode::DEVICE_IDLE:
case Mode::DISPLAY_INACTIVE:
case Mode::AUDIO_STREAMING_LOW_LATENCY:
case Mode::CAMERA_STREAMING_SECURE:
case Mode::CAMERA_STREAMING_LOW:
case Mode::CAMERA_STREAMING_MID:
case Mode::CAMERA_STREAMING_HIGH:
case Mode::VR:
//省略
}
return ndk::ScopedAStatus::ok();
}
上面的#ifdef TAP_TO_WAKE_NODE这个宏已经在前面文章给大家剖析过,所以很容易知道这里的TAP_TO_WAKE_NODE值
TARGET_TAP_TO_WAKE_NODE := "/sys/class/touch/tpnode/synaptics/wake_gesture"
实际上到这里就很清楚hal中干的事情,就是对/sys/class/touch/tpnode/synaptics/wake_gesture写入对应的值0或1,具体也可以通过设置中开关,然后验证/sys/class/touch/tpnode/synaptics/wake_gesture的值
adb shell cat /sys/class/touch/tpnode/synaptics/wake_gesture
1
adb shell cat /sys/class/touch/tpnode/synaptics/wake_gesture
0
那么剩下的事就是驱动层面实现的事情,本篇文章就不对驱动部分进行深入剖析了。
更多framework详细代码和资料参考如下链接
投屏专题部分:
https://mp.weixin.qq.com/s/IGm6VHMiAOPejC_H3N_SNg
hal+perfetto+surfaceflinger
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
其他课程七件套专题:
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw
视频试看:
https://www.bilibili.com/video/BV1wc41117L4/
参考相关链接:
https://blog.csdn.net/zhimokf/article/details/137958615
更多framework假威风耗:androidframework007