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 "android.hardware.health@2.1-impl-zuma"
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__
126
FileExists(const std::string & filename)127 static bool FileExists(const std::string &filename) {
128 struct stat buffer;
129
130 return stat(filename.c_str(), &buffer) == 0;
131 }
132
private_healthd_board_init(struct healthd_config * hc)133 void private_healthd_board_init(struct healthd_config *hc) {
134 std::string tcpmPsyName;
135 ChargerDetect::populateTcpmPsyName(&tcpmPsyName);
136 hc->ignorePowerSupplyNames.push_back(android::String8(tcpmPsyName.c_str()));
137 needs_wlc_updates = FileExists(kWlcCapacity);
138 if (needs_wlc_updates == false) {
139 battDefender.setWirelessNotSupported();
140 }
141 }
142
private_healthd_board_battery_update(HealthInfo * health_info)143 int private_healthd_board_battery_update(HealthInfo *health_info) {
144 deviceHealth.update(health_info);
145 battMetricsLogger.logBatteryProperties(*health_info);
146 shutdownMetrics.logShutdownVoltage(*health_info);
147 // Allow BatteryDefender to override online properties
148 ChargerDetect::onlineUpdate(health_info);
149 battDefender.update(health_info);
150
151 if (needs_wlc_updates &&
152 !android::base::WriteStringToFile(std::to_string(health_info->batteryLevel), kWlcCapacity))
153 LOG(INFO) << "Unable to write battery level to wireless capacity";
154
155 return 0;
156 }
157 #endif // __ANDROID_RECOVERY__
158
private_get_storage_info(std::vector<StorageInfo> * vec_storage_info)159 void private_get_storage_info(std::vector<StorageInfo> *vec_storage_info) {
160 vec_storage_info->resize(1);
161 StorageInfo *storage_info = &vec_storage_info->at(0);
162
163 read_ufs_version(storage_info);
164
165 auto time_now = std::chrono::system_clock::now();
166 auto time_delta = time_now - ufs_last_query_time;
167 auto hoursElapsed = std::chrono::duration_cast<std::chrono::hours>(time_delta);
168 if (hoursElapsed >= kUfsQueryIntervalHours) {
169 ufs_last_query_time = time_now;
170 read_value_from_file(kUfsHealthEol, &eol);
171 read_value_from_file(kUfsHealthLifetimeA, &lifetimeA);
172 read_value_from_file(kUfsHealthLifetimeB, &lifetimeB);
173 LOG(INFO) << "ufs: eol=" << eol << " lifetimeA=" << lifetimeA << " lifetimeB=" << lifetimeB;
174 }
175 storage_info->eol = eol;
176 storage_info->lifetimeA = lifetimeA;
177 storage_info->lifetimeB = lifetimeB;
178
179 return;
180 }
181
private_get_disk_stats(std::vector<DiskStats> * vec_stats)182 void private_get_disk_stats(std::vector<DiskStats> *vec_stats) {
183 vec_stats->resize(1);
184 DiskStats *stats = &vec_stats->at(0);
185
186 auto stream = assert_open(kDiskStatsFile);
187 // Regular diskstats entries
188 stream >> stats->reads >> stats->readMerges >> stats->readSectors >>
189 stats->readTicks >> stats->writes >> stats->writeMerges >>
190 stats->writeSectors >> stats->writeTicks >> stats->ioInFlight >>
191 stats->ioTicks >> stats->ioInQueue;
192 return;
193 }
194 } // anonymous namespace
195
196 namespace aidl::android::hardware::health::implementation {
197 class HealthImpl : public Health {
198 public:
HealthImpl(std::string_view instance_name,std::unique_ptr<healthd_config> && config)199 HealthImpl(std::string_view instance_name, std::unique_ptr<healthd_config>&& config)
200 : Health(std::move(instance_name), std::move(config)) {}
201
202 ndk::ScopedAStatus getDiskStats(std::vector<DiskStats>* out) override;
203 ndk::ScopedAStatus getStorageInfo(std::vector<StorageInfo>* out) override;
204
205 protected:
206 void UpdateHealthInfo(HealthInfo* health_info) override;
207
208 };
209
UpdateHealthInfo(HealthInfo * health_info)210 void HealthImpl::UpdateHealthInfo(HealthInfo* health_info) {
211 private_healthd_board_battery_update(health_info);
212 }
213
getStorageInfo(std::vector<StorageInfo> * out)214 ndk::ScopedAStatus HealthImpl::getStorageInfo(std::vector<StorageInfo>* out)
215 {
216 private_get_storage_info(out);
217 if (out->empty()) {
218 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
219 }
220 return ndk::ScopedAStatus::ok();
221 }
222
getDiskStats(std::vector<DiskStats> * out)223 ndk::ScopedAStatus HealthImpl::getDiskStats(std::vector<DiskStats>* out)
224 {
225 private_get_disk_stats(out);
226 if (out->empty()) {
227 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
228 }
229 return ndk::ScopedAStatus::ok();
230 }
231
232 } // namespace aidl::android::hardware::health::implementation
233
234 #ifndef __ANDROID_RECOVERY__
235 namespace aidl::android::hardware::health {
236 class ChargerCallbackImpl : public ChargerCallback {
237 public:
ChargerCallbackImpl(const std::shared_ptr<Health> & service)238 ChargerCallbackImpl(const std::shared_ptr<Health>& service) : ChargerCallback(service) {}
ChargerEnableSuspend()239 bool ChargerEnableSuspend() override { return true; }
240 };
241 } //namespace aidl::android::hardware::health
242 #endif // !__ANDROID_RECOVERY__
243
main(int argc,char ** argv)244 int main(int argc, char **argv) {
245 using ::aidl::android::hardware::health::implementation::HealthImpl;
246
247 // Use kernel logging in recovery
248 #ifdef __ANDROID_RECOVERY__
249 android::base::InitLogging(argv, android::base::KernelLogger);
250 #endif
251
252 auto config = std::make_unique<healthd_config>();
253 InitHealthdConfig(config.get());
254
255 private_healthd_board_init(config.get());
256
257 auto binder =
258 ndk::SharedRefBase::make<HealthImpl>("default"sv, std::move(config));
259
260 if (argc >= 2 && argv[1] == "--charger"sv) {
261 // In regular mode, start charger UI.
262 #ifndef __ANDROID_RECOVERY__
263 LOG(INFO) << "Starting charger mode with UI.";
264 auto charger_callback = std::make_shared<aidl::android::hardware::health::ChargerCallbackImpl>(binder);
265 return ChargerModeMain(binder, charger_callback);
266 #endif
267 // In recovery, ignore --charger arg.
268 LOG(INFO) << "Starting charger mode without UI.";
269 } else {
270 LOG(INFO) << "Starting health HAL.";
271 }
272
273 auto hal_health_loop = std::make_shared<HalHealthLoop>(binder, binder);
274 return hal_health_loop->StartLoop();
275 }
276