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 #define LOG_TAG "[email protected]"
17 #include <android-base/logging.h>
18 
19 #include <android-base/file.h>
20 #include <android-base/parseint.h>
21 #include <android-base/strings.h>
22 #include <android/hardware/health/translate-ndk.h>
23 #include <health-impl/Health.h>
24 #include <health/utils.h>
25 
26 // Recovery doesn't have libpixelhealth and charger mode
27 #ifndef __ANDROID_RECOVERY__
28 #include <health-impl/ChargerUtils.h>
29 #include <pixelhealth/BatteryDefender.h>
30 #include <pixelhealth/BatteryMetricsLogger.h>
31 #include <pixelhealth/ChargerDetect.h>
32 #include <pixelhealth/DeviceHealth.h>
33 #include <pixelhealth/LowBatteryShutdownMetrics.h>
34 #endif // !__ANDROID_RECOVERY__
35 
36 #include <chrono>
37 #include <fstream>
38 #include <iomanip>
39 #include <string>
40 #include <vector>
41 
42 namespace {
43 
44 using namespace std::literals;
45 
46 using aidl::android::hardware::health::DiskStats;
47 using aidl::android::hardware::health::HalHealthLoop;
48 using aidl::android::hardware::health::HealthInfo;
49 using aidl::android::hardware::health::StorageInfo;
50 using android::hardware::health::InitHealthdConfig;
51 
52 #ifndef __ANDROID_RECOVERY__
53 using aidl::android::hardware::health::charger::ChargerCallback;
54 using aidl::android::hardware::health::charger::ChargerModeMain;
55 using hardware::google::pixel::health::BatteryDefender;
56 using hardware::google::pixel::health::BatteryMetricsLogger;
57 using hardware::google::pixel::health::DeviceHealth;
58 using hardware::google::pixel::health::LowBatteryShutdownMetrics;
59 using hardware::google::pixel::health::ChargerDetect;
60 
61 #define FG_DIR "/sys/class/power_supply/battery"
62 constexpr char kBatteryResistance[] {FG_DIR "/resistance"};
63 constexpr char kBatteryOCV[] {FG_DIR "/voltage_ocv"};
64 constexpr char kVoltageAvg[] {FG_DIR "/voltage_now"};
65 
66 #define WLC_DIR "/sys/class/power_supply/wireless"
67 
68 static BatteryDefender battDefender(WLC_DIR "/present",
69     "/sys/devices/platform/google,charger/charge_start_level",
70     "/sys/devices/platform/google,charger/charge_stop_level");
71 static BatteryMetricsLogger battMetricsLogger(kBatteryResistance, kBatteryOCV);
72 static LowBatteryShutdownMetrics shutdownMetrics(kVoltageAvg);
73 static DeviceHealth deviceHealth;
74 #endif // !__ANDROID_RECOVERY__
75 
76 #define UFS_DIR "/dev/sys/block/bootdevice"
77 constexpr char kUfsHealthEol[]{UFS_DIR "/health_descriptor/eol_info"};
78 constexpr char kUfsHealthLifetimeA[]{UFS_DIR "/health_descriptor/life_time_estimation_a"};
79 constexpr char kUfsHealthLifetimeB[]{UFS_DIR "/health_descriptor/life_time_estimation_b"};
80 constexpr char kUfsVersion[]{UFS_DIR "/device_descriptor/specification_version"};
81 constexpr char kDiskStatsFile[]{"/sys/block/sda/stat"};
82 
83 static std::string ufs_version;
84 static uint16_t eol;
85 static uint16_t lifetimeA;
86 static uint16_t lifetimeB;
87 static std::chrono::system_clock::time_point ufs_last_query_time;
88 constexpr auto kUfsQueryIntervalHours = std::chrono::hours{24};
89 
90 #ifndef __ANDROID_RECOVERY__
91 static bool needs_wlc_updates = false;
92 constexpr char kWlcCapacity[]{WLC_DIR "/capacity"};
93 #endif // !__ANDROID_RECOVERY__
94 
assert_open(const std::string & path)95 std::ifstream assert_open(const std::string &path) {
96   std::ifstream stream(path);
97   if (!stream.is_open()) {
98     LOG(WARNING) << "Cannot read " << path;
99   }
100   return stream;
101 }
102 
103 template <typename T>
read_value_from_file(const std::string & path,T * field)104 void read_value_from_file(const std::string &path, T *field) {
105   auto stream = assert_open(path);
106   stream.unsetf(std::ios_base::basefield);
107   stream >> *field;
108 }
109 
read_ufs_version(StorageInfo * info)110 void read_ufs_version(StorageInfo *info) {
111   if (ufs_version.empty()) {
112     uint64_t value;
113     read_value_from_file(kUfsVersion, &value);
114     std::stringstream ss;
115     ss << "ufs " << std::hex << value;
116     ufs_version = ss.str();
117     LOG(INFO) << "ufs: " << ufs_version << " detected";
118   }
119   info->version = ufs_version;
120 }
121 
122 #ifdef __ANDROID_RECOVERY__
private_healthd_board_init(struct healthd_config *)123 void private_healthd_board_init(struct healthd_config *) {}
private_healthd_board_battery_update(HealthInfo *)124 int private_healthd_board_battery_update(HealthInfo *) { return 0; }
125 #else // !__ANDROID__RECOVERY__
FileExists(const std::string & filename)126 static bool FileExists(const std::string &filename) {
127   struct stat buffer;
128 
129   return stat(filename.c_str(), &buffer) == 0;
130 }
131 
private_healthd_board_init(struct healthd_config * hc)132 void private_healthd_board_init(struct healthd_config *hc) {
133   std::string tcpmPsyName;
134   ChargerDetect::populateTcpmPsyName(&tcpmPsyName);
135   hc->ignorePowerSupplyNames.push_back(android::String8(tcpmPsyName.c_str()));
136   needs_wlc_updates = FileExists(kWlcCapacity);
137   if (needs_wlc_updates == false) {
138     battDefender.setWirelessNotSupported();
139   }
140 }
141 
private_healthd_board_battery_update(HealthInfo * health_info)142 int private_healthd_board_battery_update(HealthInfo *health_info) {
143   deviceHealth.update(health_info);
144   battMetricsLogger.logBatteryProperties(*health_info);
145   shutdownMetrics.logShutdownVoltage(*health_info);
146   // Allow BatteryDefender to override online properties
147   ChargerDetect::onlineUpdate(health_info);
148   battDefender.update(health_info);
149 
150   if (needs_wlc_updates &&
151       !android::base::WriteStringToFile(std::to_string(health_info->batteryLevel), kWlcCapacity))
152       LOG(INFO) << "Unable to write battery level to wireless capacity";
153 
154   return 0;
155 }
156 #endif // __ANDROID_RECOVERY__
157 
private_get_storage_info(std::vector<StorageInfo> * vec_storage_info)158 void private_get_storage_info(std::vector<StorageInfo> *vec_storage_info) {
159   vec_storage_info->resize(1);
160   StorageInfo *storage_info = &vec_storage_info->at(0);
161 
162   read_ufs_version(storage_info);
163 
164   auto time_now = std::chrono::system_clock::now();
165   auto time_delta = time_now - ufs_last_query_time;
166   auto hoursElapsed = std::chrono::duration_cast<std::chrono::hours>(time_delta);
167   if (hoursElapsed >= kUfsQueryIntervalHours) {
168     ufs_last_query_time = time_now;
169     read_value_from_file(kUfsHealthEol, &eol);
170     read_value_from_file(kUfsHealthLifetimeA, &lifetimeA);
171     read_value_from_file(kUfsHealthLifetimeB, &lifetimeB);
172     LOG(INFO) << "ufs: eol=" << eol << " lifetimeA=" << lifetimeA << " lifetimeB=" << lifetimeB;
173   }
174   storage_info->eol = eol;
175   storage_info->lifetimeA = lifetimeA;
176   storage_info->lifetimeB = lifetimeB;
177 
178   return;
179 }
180 
private_get_disk_stats(std::vector<DiskStats> * vec_stats)181 void private_get_disk_stats(std::vector<DiskStats> *vec_stats) {
182   vec_stats->resize(1);
183   DiskStats *stats = &vec_stats->at(0);
184 
185   auto stream = assert_open(kDiskStatsFile);
186   // Regular diskstats entries
187   stream >> stats->reads >> stats->readMerges >> stats->readSectors >>
188       stats->readTicks >> stats->writes >> stats->writeMerges >>
189       stats->writeSectors >> stats->writeTicks >> stats->ioInFlight >>
190       stats->ioTicks >> stats->ioInQueue;
191   return;
192 }
193 }  // anonymous namespace
194 
195 namespace aidl::android::hardware::health::implementation {
196 class HealthImpl : public Health {
197  public:
HealthImpl(std::string_view instance_name,std::unique_ptr<healthd_config> && config)198   HealthImpl(std::string_view instance_name, std::unique_ptr<healthd_config>&& config)
199     : Health(std::move(instance_name), std::move(config)) {}
200 
201     ndk::ScopedAStatus getDiskStats(std::vector<DiskStats>* out) override;
202     ndk::ScopedAStatus getStorageInfo(std::vector<StorageInfo>* out) override;
203 
204  protected:
205   void UpdateHealthInfo(HealthInfo* health_info) override;
206 
207 };
208 
UpdateHealthInfo(HealthInfo * health_info)209 void HealthImpl::UpdateHealthInfo(HealthInfo* health_info) {
210   private_healthd_board_battery_update(health_info);
211 }
212 
getStorageInfo(std::vector<StorageInfo> * out)213 ndk::ScopedAStatus HealthImpl::getStorageInfo(std::vector<StorageInfo>* out)
214 {
215   private_get_storage_info(out);
216   if (out->empty()) {
217     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
218   }
219   return ndk::ScopedAStatus::ok();
220 }
221 
getDiskStats(std::vector<DiskStats> * out)222 ndk::ScopedAStatus HealthImpl::getDiskStats(std::vector<DiskStats>* out)
223 {
224   private_get_disk_stats(out);
225   if (out->empty()) {
226     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
227   }
228   return ndk::ScopedAStatus::ok();
229 }
230 
231 }  // namespace aidl::android::hardware::health::implementation
232 
main(int argc,char ** argv)233 int main(int argc, char **argv) {
234   using ::aidl::android::hardware::health::implementation::HealthImpl;
235 
236   // Use kernel logging in recovery
237 #ifdef __ANDROID_RECOVERY__
238   android::base::InitLogging(argv, android::base::KernelLogger);
239 #endif
240 
241   auto config = std::make_unique<healthd_config>();
242   InitHealthdConfig(config.get());
243 
244   private_healthd_board_init(config.get());
245 
246   auto binder =
247       ndk::SharedRefBase::make<HealthImpl>("default"sv, std::move(config));
248 
249   if (argc >= 2 && argv[1] == "--charger"sv) {
250     // In regular mode, start charger UI.
251 #ifndef __ANDROID_RECOVERY__
252     LOG(INFO) << "Starting charger mode with UI.";
253     return ChargerModeMain(binder, std::make_shared<ChargerCallback>(binder));
254 #endif
255     // In recovery, ignore --charger arg.
256     LOG(INFO) << "Starting charger mode without UI.";
257   } else {
258     LOG(INFO) << "Starting health HAL.";
259   }
260 
261   auto hal_health_loop = std::make_shared<HalHealthLoop>(binder, binder);
262   return hal_health_loop->StartLoop();
263 }
264