blob: dc5c459d7182ce68001c03eabb959f641a47ab34 [file] [log] [blame]
Yifan Hongb7cd45f2017-11-13 18:47:03 -08001/*
2 * Copyright (C) 2017 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 LOG_TAG "charger_test"
18#include <android/log.h>
19
20#include <chrono>
21#include <condition_variable>
22#include <fstream>
23#include <iostream>
Yifan Hong7dcf7b02019-10-08 17:27:11 -070024#include <memory>
Yifan Hongb7cd45f2017-11-13 18:47:03 -080025#include <mutex>
26#include <streambuf>
27#include <string>
28#include <thread>
29#include <vector>
30
Yifan Hong7dcf7b02019-10-08 17:27:11 -070031#include <health/utils.h>
32#include <health2impl/Health.h>
33
Yifan Hongb5d70332021-10-20 17:15:32 -070034#include "healthd_mode_charger_hidl.h"
Yifan Hong7dcf7b02019-10-08 17:27:11 -070035
36using android::hardware::health::InitHealthdConfig;
37using android::hardware::health::V2_1::HealthInfo;
38using android::hardware::health::V2_1::IHealth;
39using android::hardware::health::V2_1::implementation::Health;
Yifan Hongb7cd45f2017-11-13 18:47:03 -080040
41#define LOG_THIS(fmt, ...) \
42 ALOGE(fmt, ##__VA_ARGS__); \
43 printf(fmt "\n", ##__VA_ARGS__);
44
45template <typename T>
46class Atomic {
47 public:
48 Atomic(T&& init) : mValue(std::move(init)) {}
49 void set(T&& newVal) {
50 {
51 std::lock_guard<std::mutex> lock(mMutex);
52 mValue = std::move(newVal);
53 }
54 mChanged.notify_all();
55 }
56 bool waitFor(long ms, const T& expectVal) {
57 std::unique_lock<std::mutex> lock(mMutex);
58 return mChanged.wait_for(lock, std::chrono::milliseconds(ms),
59 [this, &expectVal] { return mValue == expectVal; });
60 }
61 private:
62 std::mutex mMutex;
63 std::condition_variable mChanged;
64 T mValue;
65};
66
67Atomic<bool>& getUpdateNotifier() {
68 static Atomic<bool> val(false);
69 return val;
70}
71
72int energyCounter(int64_t* counter) {
73 *counter = 0xEC12345;
74 return 0;
75}
76
77const char* createFile(const char* path, const char* content) {
78 std::ofstream stream(path);
79 if (!stream.is_open()) {
80 LOG_THIS("Cannot create file %s", path);
81 return NULL;
82 }
83 stream << content << std::endl;
84 stream.close();
85 return path;
86}
87
88std::string openToString(const char* path) {
89 std::ifstream stream(path);
90 if (!stream.is_open()) {
91 LOG_THIS("Cannot open file %s", path);
92 return "";
93 }
94 return std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
95}
96
97int expectContains(const std::string& content, const std::vector<std::string>& fields) {
98 int status = 0;
99 for (const auto& field : fields) {
100 auto pos = content.find(field);
101 if (pos == std::string::npos) {
102 LOG_THIS("Cannot find substr '%s'", field.c_str());
103 status = 1;
104 }
105 }
106 return status;
107}
108
Yifan Hong25eb37a2017-11-13 13:31:35 -0800109::android::hardware::hidl_handle createHidlHandle(const char* filepath) {
110 int fd = creat(filepath, S_IRUSR | S_IWUSR);
111 if (fd < 0) return {};
112 native_handle_t* nativeHandle = native_handle_create(1, 0);
113 nativeHandle->data[0] = fd;
114 ::android::hardware::hidl_handle handle;
115 handle.setTo(nativeHandle, true /* shouldOwn */);
116 return handle;
117}
118
Yifan Hongb7cd45f2017-11-13 18:47:03 -0800119void healthd_board_init(struct healthd_config* config) {
120 config->periodic_chores_interval_fast = 60;
121 config->periodic_chores_interval_slow = 600;
122
123 config->batteryStatusPath = createFile("/data/local/tmp/batteryStatus", "Not charging");
124 config->batteryHealthPath = createFile("/data/local/tmp/batteryHealth", "Unspecified failure");
125 config->batteryPresentPath = createFile("/data/local/tmp/batteryPresent", "1");
126 config->batteryCapacityPath = createFile("/data/local/tmp/batteryCapacity", "47");
127 config->batteryVoltagePath = createFile("/data/local/tmp/batteryVoltage", "45000");
128 config->batteryTemperaturePath = createFile("/data/local/tmp/batteryTemperature", "987");
129 config->batteryTechnologyPath = createFile("/data/local/tmp/batteryTechnology", "NiCd");
130 config->batteryCurrentNowPath = createFile("/data/local/tmp/batteryCurrentNow", "99000");
131 config->batteryCurrentAvgPath = createFile("/data/local/tmp/batteryCurrentAvg", "98000");
132 config->batteryChargeCounterPath = createFile("/data/local/tmp/batteryChargeCounter", "600");
133 config->batteryFullChargePath = createFile("/data/local/tmp/batteryFullCharge", "3515547");
134 config->batteryCycleCountPath = createFile("/data/local/tmp/batteryCycleCount", "77");
135
136 config->energyCounter = energyCounter;
137 config->boot_min_cap = 50;
138 config->screen_on = NULL;
139}
140
Yifan Hong7dcf7b02019-10-08 17:27:11 -0700141class TestHealth : public Health {
142 protected:
143 using Health::Health;
144 void UpdateHealthInfo(HealthInfo*) override { getUpdateNotifier().set(true /* updated */); }
145};
Yifan Hongb7cd45f2017-11-13 18:47:03 -0800146
Yifan Hong7dcf7b02019-10-08 17:27:11 -0700147int main(int /*argc*/, char** /*argv*/) {
Yifan Hongb7cd45f2017-11-13 18:47:03 -0800148 const char* dumpFile = "/data/local/tmp/dump.txt";
149
Yifan Hong7dcf7b02019-10-08 17:27:11 -0700150 auto config = std::make_unique<healthd_config>();
151 InitHealthdConfig(config.get());
152 healthd_board_init(config.get());
153 sp<IHealth> passthrough = new TestHealth(std::move(config));
154
Yifan Hongb7cd45f2017-11-13 18:47:03 -0800155 std::thread bgThread([=] {
Yifan Hongb5d70332021-10-20 17:15:32 -0700156 android::ChargerHidl charger(passthrough);
Yifan Hong7dcf7b02019-10-08 17:27:11 -0700157 charger.StartLoop();
Yifan Hongb7cd45f2017-11-13 18:47:03 -0800158 });
159
160 // wait for healthd_init to finish
161 if (!getUpdateNotifier().waitFor(1000 /* wait ms */, true /* updated */)) {
162 LOG_THIS("Time out.");
163 exit(1);
164 }
165
Yifan Hong7dcf7b02019-10-08 17:27:11 -0700166 passthrough->debug(createHidlHandle(dumpFile), {} /* options */);
Yifan Hongb7cd45f2017-11-13 18:47:03 -0800167
168 std::string content = openToString(dumpFile);
169 int status = expectContains(content, {
170 "status: 4",
171 "health: 6",
172 "present: 1",
173 "level: 47",
174 "voltage: 45",
175 "temp: 987",
176 "current now: 99000",
177 "current avg: 98000",
178 "charge counter: 600",
179 "current now: 99",
180 "cycle count: 77",
181 "Full charge: 3515547"
182 });
183
184 if (status == 0) {
185 LOG_THIS("Test success.");
186 } else {
187 LOG_THIS("Actual dump:\n%s", content.c_str());
188 }
189
190 exit(status); // force bgThread to exit
191}