Home | History | Annotate | Download | only in external
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define DEBUG false  // STOPSHIP if true
     18 #include "Log.h"
     19 
     20 #include <android/hardware/power/stats/1.0/IPowerStats.h>
     21 
     22 #include <vector>
     23 
     24 #include "PowerStatsPuller.h"
     25 #include "stats_log_util.h"
     26 
     27 using android::hardware::hidl_vec;
     28 using android::hardware::power::stats::V1_0::IPowerStats;
     29 using android::hardware::power::stats::V1_0::EnergyData;
     30 using android::hardware::power::stats::V1_0::RailInfo;
     31 using android::hardware::power::stats::V1_0::Status;
     32 using android::hardware::Return;
     33 using android::hardware::Void;
     34 
     35 using std::make_shared;
     36 using std::shared_ptr;
     37 
     38 namespace android {
     39 namespace os {
     40 namespace statsd {
     41 
     42 static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHal = nullptr;
     43 static std::mutex gPowerStatsHalMutex;
     44 static bool gPowerStatsExist = true; // Initialized to ensure making a first attempt.
     45 static std::vector<RailInfo> gRailInfo;
     46 
     47 struct PowerStatsPullerDeathRecipient : virtual public hardware::hidl_death_recipient {
     48     virtual void serviceDied(uint64_t cookie,
     49             const wp<android::hidl::base::V1_0::IBase>& who) override {
     50         // The HAL just died. Reset all handles to HAL services.
     51         std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
     52         gPowerStatsHal = nullptr;
     53     }
     54 };
     55 
     56 static sp<PowerStatsPullerDeathRecipient> gDeathRecipient = new PowerStatsPullerDeathRecipient();
     57 
     58 static bool getPowerStatsHalLocked() {
     59     if (gPowerStatsHal == nullptr && gPowerStatsExist) {
     60         gPowerStatsHal = android::hardware::power::stats::V1_0::IPowerStats::getService();
     61         if (gPowerStatsHal == nullptr) {
     62             ALOGW("Couldn't load power.stats HAL service");
     63             gPowerStatsExist = false;
     64         } else {
     65             // Link death recipient to power.stats service handle
     66             hardware::Return<bool> linked = gPowerStatsHal->linkToDeath(gDeathRecipient, 0);
     67             if (!linked.isOk()) {
     68                 ALOGE("Transaction error in linking to power.stats HAL death: %s",
     69                         linked.description().c_str());
     70                 gPowerStatsHal = nullptr;
     71                 return false;
     72             } else if (!linked) {
     73                 ALOGW("Unable to link to power.stats HAL death notifications");
     74                 // We should still continue even though linking failed
     75             }
     76         }
     77     }
     78     return gPowerStatsHal != nullptr;
     79 }
     80 
     81 PowerStatsPuller::PowerStatsPuller() : StatsPuller(android::util::ON_DEVICE_POWER_MEASUREMENT) {
     82 }
     83 
     84 bool PowerStatsPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
     85     std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
     86 
     87     if (!getPowerStatsHalLocked()) {
     88         ALOGE("power.stats Hal not loaded");
     89         return false;
     90     }
     91 
     92     int64_t wallClockTimestampNs = getWallClockNs();
     93     int64_t elapsedTimestampNs = getElapsedRealtimeNs();
     94 
     95     data->clear();
     96 
     97     // Pull getRailInfo if necessary
     98     if (gRailInfo.empty()) {
     99         bool resultSuccess = true;
    100         Return<void> ret = gPowerStatsHal->getRailInfo(
    101                 [&resultSuccess](const hidl_vec<RailInfo> &list, Status status) {
    102                     resultSuccess = (status == Status::SUCCESS || status == Status::NOT_SUPPORTED);
    103                     if (status != Status::SUCCESS) return;
    104 
    105                     gRailInfo.reserve(list.size());
    106                     for (size_t i = 0; i < list.size(); ++i) {
    107                         gRailInfo.push_back(list[i]);
    108                     }
    109                 });
    110         if (!resultSuccess || !ret.isOk()) {
    111             ALOGE("power.stats getRailInfo() failed. Description: %s", ret.description().c_str());
    112             gPowerStatsHal = nullptr;
    113             return false;
    114         }
    115         // If SUCCESS but empty, or if NOT_SUPPORTED, then never try again.
    116         if (gRailInfo.empty()) {
    117             ALOGE("power.stats has no rail information");
    118             gPowerStatsExist = false; // No rail info, so never try again.
    119             return false;
    120         }
    121     }
    122 
    123     // Pull getEnergyData and write the data out
    124     const hidl_vec<uint32_t> desiredRailIndices; // Empty vector indicates we want all.
    125     bool resultSuccess = true;
    126     Return<void> ret = gPowerStatsHal->getEnergyData(desiredRailIndices,
    127                 [&data, wallClockTimestampNs, elapsedTimestampNs, &resultSuccess]
    128                 (hidl_vec<EnergyData> energyDataList, Status status) {
    129                     resultSuccess = (status == Status::SUCCESS);
    130                     if (!resultSuccess) return;
    131 
    132                     for (size_t i = 0; i < energyDataList.size(); i++) {
    133                         const EnergyData& energyData = energyDataList[i];
    134 
    135                         if (energyData.index >= gRailInfo.size()) {
    136                             ALOGE("power.stats getEnergyData() returned an invalid rail index %u.",
    137                                     energyData.index);
    138                             resultSuccess = false;
    139                             return;
    140                         }
    141                         const RailInfo& rail = gRailInfo[energyData.index];
    142 
    143                         auto ptr = make_shared<LogEvent>(android::util::ON_DEVICE_POWER_MEASUREMENT,
    144                               wallClockTimestampNs, elapsedTimestampNs);
    145                         ptr->write(rail.subsysName);
    146                         ptr->write(rail.railName);
    147                         ptr->write(energyData.timestamp);
    148                         ptr->write(energyData.energy);
    149                         ptr->init();
    150                         data->push_back(ptr);
    151 
    152                         VLOG("power.stat: %s.%s: %llu, %llu",
    153                              rail.subsysName.c_str(),
    154                              rail.railName.c_str(),
    155                              (unsigned long long)energyData.timestamp,
    156                              (unsigned long long)energyData.energy);
    157                     }
    158                 });
    159     if (!resultSuccess || !ret.isOk()) {
    160         ALOGE("power.stats getEnergyData() failed. Description: %s", ret.description().c_str());
    161         gPowerStatsHal = nullptr;
    162         return false;
    163     }
    164     return true;
    165 }
    166 
    167 }  // namespace statsd
    168 }  // namespace os
    169 }  // namespace android
    170