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