android 9.0 getIntProperty获取系统当前电量流程分析(二)

接着看上一篇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的值;

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值