接着看上一篇android 9.0 getIntProperty获取系统当前电量流程分析(一),分析getCapacity在HIDL中的实现
service.getCapacity((int result, int value) -> {
outResult.value = result;
if (result == Result.SUCCESS) prop.setLong(value);
});
这个service.getCapacity()中参数其实是个回调函数;
if (result == Result.SUCCESS) prop.setLong(value);在这里设置我们的电量。
对应上一篇文中 的返回值ret = prop.getLong();//当前电量返回结果
/hardware/interfaces/health/2.0/default/Health.cpp
Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
return Void();
}
getCapacity很简单,直接调用的是getProperty。
继续跟 getProperty(),到这里正菜算是上了。
getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
void getProperty(const std::unique_ptr<BatteryMonitor>& monitor, int id, T defaultValue,
const std::function<void(Result, T)>& callback) {
struct BatteryProperty prop;
T ret = defaultValue;
Result result = Result::SUCCESS;
status_t err = monitor->getProperty(static_cast<int>(id), &prop);
if (err != OK) {
LOG(DEBUG) << "getProperty(" << id << ")"
<< " fails: (" << err << ") " << strerror(-err);
} else {
ret = static_cast<T>(prop.valueInt64);
}
switch (err) {
case OK:
result = Result::SUCCESS;
break;
case NAME_NOT_FOUND:
result = Result::NOT_SUPPORTED;
break;
default:
result = Result::UNKNOWN;
break;
}
callback(result, static_cast<T>(ret));
}
先来看看getProperty传进来的参数,搞懂具体对应的是谁。
1,const std::unique_ptr<BatteryMonitor>& monitor
对应的是system/core/healthd/BatteryMonitor.cpp,这个BatteryMonitor其实就是用来管理整个电量信息。后面会说到。
2,int id :
在getProperty() 中调用getProperty时传入的是BATTERY_PROP_CAPACITY ,这个定义在 frameworks/native/services/batteryservice/include/batteryservice/BatteryService.h
BATTERY_PROP_CAPACITY = 4, // equals BATTERY_PROPERTY_CAPACITY // 还记得上层获取电量传入的是哪个值吗?
这个值为什么能在Health.cpp中使用呢? 看看以下头文件的包含关系就明白了
Health.h | #include <healthd/BatteryMonitor.h>---> #include <batteryservice/BatteryService.h> |
3,T defaultValue:顾名思义就是默认值了
4,const std::function<void(Result, T)>& callback: 回调函数
下面开始分析getProperty具体的实现逻辑:
其实也很简单 首先调用 status_t err = monitor->getProperty(static_cast<int>(id), &prop);
后面的逻辑就是对返回结果做相应的处理,然后调用回调函数callback(result, static_cast<T>(ret));
所以还得跟具体跟踪 monitor->getProperty(static_cast<int>(id), &prop);
这个monitor,上面说了对应的是BatteryMonitor.cpp
status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
status_t ret = BAD_VALUE;
std::string buf;
val->valueInt64 = LONG_MIN;
switch(id) {
........
........
........
case BATTERY_PROP_CAPACITY:
if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
val->valueInt64 =
getIntField(mHealthdConfig->batteryCapacityPath);
ret = NO_ERROR;
} else {
ret = NAME_NOT_FOUND;
}
break;
........
........
........
return ret;
}
找到BATTERY_PROP_CAPACITY对应的case;
val->valueInt64 = getIntField(mHealthdConfig->batteryCapacityPath)数名跟参数,估计都能知道是对读取文件节点的操作了。
读取的值存在BatteryProperty结构体的valueInt64中。
来看下参数 mHealthdConfig->batteryChargeCounterPath具体是哪个节点?
它是在BatteryMonitor::init中被初始化的
void BatteryMonitor::init(struct healthd_config *hc) {
String8 path;
char pval[PROPERTY_VALUE_MAX];
mHealthdConfig = hc;
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
if (dir == NULL) {
KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
} else {
struct dirent* entry;
while ((entry = readdir(dir.get()))) {
const char* name = entry->d_name;
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
// Look for "type" file in each subdirectory
path.clear();
path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
switch(readPowerSupplyType(path)) {
case ANDROID_POWER_SUPPLY_TYPE_AC:
case ANDROID_POWER_SUPPLY_TYPE_USB:
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
path.clear();
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
if (access(path.string(), R_OK) == 0)
mChargerNames.add(String8(name));
break;
case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
if (mHealthdConfig->batteryCapacityPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,
name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryCapacityPath = path;
}
}
#define POWER_SUPPLY_SUBSYSTEM "power_supply"
#define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
看看POWER_SUPPLY_SYSFS_PATH 下面有些什么?
定义了四种充电类型的设备,我们要获取的是电池的电量,对应的是battery。
1,首先opendir了 POWER_SUPPLY_SYSFS_PATH
2,接着在一个大的while循环中主要做的操作就是遍历文件 / /Look for "type" file in each subdirectory。
3,接着调用readPowerSupplyType(path),根据传入的路径返回充电类型,之后在switch中匹配相应充电类型;
BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
std::string buf;
int ret;
struct sysfsStringEnumMap supplyTypeMap[] = {
{ "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN },
{ "Battery", ANDROID_POWER_SUPPLY_TYPE_BATTERY },
{ "UPS", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "Mains", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "USB", ANDROID_POWER_SUPPLY_TYPE_USB },
{ "USB_DCP", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "USB_C", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC },
{ "USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB },
{ "Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS },
{ NULL, 0 },
};
if (readFromFile(path, &buf) <= 0)
return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
ret = mapSysfsString(buf.c_str(), supplyTypeMap);
if (ret < 0) {
KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
}
return static_cast<BatteryMonitor::PowerSupplyType>(ret);
}
name即是Battery,
所以通过 path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,name);
即变成:/sys/class/power_supply/battery/capacity
mHealthdConfig->batteryCapacityPath = path; //sys/class/power_supply/battery/capacity
到此为止,需要读取的节点已经构建ok了。
看看getIntFiled的实现:
int BatteryMonitor::getIntField(const String8& path) {
std::string buf;
int value = 0;
if (readFromFile(path, &buf) > 0)
android::base::ParseInt(buf, &value);
return value;
}
这个readFromFile就不用跟了,最后肯定是open,read,close操作了。主要是知道读取的节点是哪个就行了。
用adb 验证一下:
val->valueInt64 = getIntField(mHealthdConfig->batteryCapacityPath)
val->valueInt64 就拿到了节点的数据
回到Heath.cpp 的getProperty中
到目前为止
status_t err = monitor->getProperty(static_cast<int>(id), &prop); 算是分析完了;
功能就是传入一个id和struct BatteryProperty prop,根据要查询的id,读取对应的文件节点并存储在
BatteryPropert->valueInt64成员中;
往下分析:
void getProperty(const std::unique_ptr<BatteryMonitor>& monitor, int id, T defaultValue,
const std::function<void(Result, T)>& callback) {
struct BatteryProperty prop;
T ret = defaultValue;
Result result = Result::SUCCESS;
status_t err = monitor->getProperty(static_cast<int>(id), &prop);
//读取成功 err为NO_ERROR 其实值为0 跟下面的OK值是一样的
if (err != OK) {
LOG(DEBUG) << "getProperty(" << id << ")"
<< " fails: (" << err << ") " << strerror(-err);
} else {
//返回NO_ERROR 将存储在BatteryProperty中的valueInt64的值赋给ret
ret = static_cast<T>(prop.valueInt64);
}
switch (err) {
case OK:
result = Result::SUCCESS;
break;
case NAME_NOT_FOUND:
result = Result::NOT_SUPPORTED;
break;
default:
result = Result::UNKNOWN;
break;
}
//调用batteryservice传下来的回调函数,参数为Result::SUCCESS,ret
callback(result, static_cast<T>(ret));
}
service.getCapacity((int result, int value) -> {
outResult.value = result;
if (result == Result.SUCCESS) prop.setLong(value);
});
这个回调函数就做了一个动作
prop.setLong(value);//这个value即是 BatteryProperty中的valueInt64的值;