1 /*
2 * Copyright (C) 2024 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 "pixelstats: WaterEvent"
18
19 #include <aidl/android/frameworks/stats/IStats.h>
20 #include <android-base/file.h>
21 #include <android-base/properties.h>
22 #include <android-base/stringprintf.h>
23 #include <android-base/strings.h>
24 #include <android/binder_manager.h>
25 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
26 #include <pixelstats/WaterEventReporter.h>
27 #include <utils/Log.h>
28
29 #include <cinttypes>
30
31
32 namespace android {
33 namespace hardware {
34 namespace google {
35 namespace pixel {
36
37 using aidl::android::frameworks::stats::IStats;
38 using aidl::android::frameworks::stats::VendorAtom;
39 using aidl::android::frameworks::stats::VendorAtomValue;
40 using android::base::ReadFileToString;
41
42 static const char * const WATER_EVENT_DRIVER_STR = "DRIVER=h2omg";
43
WaterEventReporter()44 WaterEventReporter::WaterEventReporter() {};
45
fileExists(const std::string & path)46 static bool fileExists(const std::string &path) {
47 struct stat sb;
48
49 return stat(path.c_str(), &sb) == 0;
50 }
51
readFileToInt(const char * const path,int * val)52 static bool readFileToInt(const char *const path, int *val) {
53 std::string file_contents;
54
55 if (!ReadFileToString(path, &file_contents)) {
56 ALOGE("Unable to read %s - %s", path, strerror(errno));
57 return false;
58 } else if (sscanf(file_contents.c_str(), "%d", val) != 1) {
59 ALOGE("Unable to convert %s to int - %s", path, strerror(errno));
60 return false;
61 }
62 return true;
63 }
64
readFileToInt(const std::string & path,int * val)65 static inline bool readFileToInt(const std::string &path, int *val) {
66 return readFileToInt(path.c_str(), val);
67 }
68
logEvent(const std::shared_ptr<IStats> & stats_client,PixelAtoms::WaterEventReported::EventPoint event_point,const std::string_view sysfs_root)69 void WaterEventReporter::logEvent(const std::shared_ptr<IStats> &stats_client,
70 PixelAtoms::WaterEventReported::EventPoint event_point,
71 const std::string_view sysfs_root)
72 {
73 const std::string sysfs_path(sysfs_root);
74 static int count = 0;
75
76 if (!fileExists(sysfs_path)) {
77 ALOGE("WaterEvent path is not valid %s", sysfs_path.c_str());
78 return;
79 }
80
81 std::vector<VendorAtomValue> values(kNumOfWaterEventAtomFields, 0);
82
83 // Is this during boot or as a result of an event
84 values[PixelAtoms::WaterEventReported::kCollectionEventFieldNumber - kVendorAtomOffset] = event_point;
85
86 // Most important, what is the state of the fuse
87 int fuse_state;
88 if (readFileToInt(sysfs_path + "/fuse/status", &fuse_state)) {
89 auto &fuse_state_field = values[PixelAtoms::WaterEventReported::kFuseStateFieldNumber - kVendorAtomOffset];
90 switch (fuse_state) {
91 case 1:
92 fuse_state_field = PixelAtoms::WaterEventReported::FuseState::WaterEventReported_FuseState_BLOWN;
93 break;
94 case 0:
95 fuse_state_field = PixelAtoms::WaterEventReported::FuseState::WaterEventReported_FuseState_INTACT;
96 break;
97 default:
98 fuse_state_field = PixelAtoms::WaterEventReported::FuseState::WaterEventReported_FuseState_FUSE_STATE_UNKNOWN;
99 }
100 }
101
102 // Is the fuse enabled
103 int fuse_enable;
104 if (readFileToInt(sysfs_path + "/fuse/enable", &fuse_enable))
105 values[PixelAtoms::WaterEventReported::kFuseEnabledFieldNumber - kVendorAtomOffset] =
106 fuse_enable ? PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_ENABLED :
107 PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_DISABLED;
108
109 // Is system fault enabled
110 int fault_enable;
111 if (readFileToInt(sysfs_path + "/fault/enable", &fault_enable))
112 values[PixelAtoms::WaterEventReported::kFaultEnabledFieldNumber - kVendorAtomOffset] =
113 fault_enable ? PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_ENABLED :
114 PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_DISABLED;
115
116 const std::tuple<std::string, int> sensors[] = {
117 {"reference", PixelAtoms::WaterEventReported::kReferenceStateFieldNumber},
118 {"sensor0", PixelAtoms::WaterEventReported::kSensor0StateFieldNumber},
119 {"sensor1", PixelAtoms::WaterEventReported::kSensor1StateFieldNumber}
120 };
121
122 // Get the sensor states (including reference) from either the boot_value (if this is during
123 // startup), or the latched_value if this is the result of a uevent
124 for (const auto& e : sensors) {
125 const std::string &sensor_path = std::get<0>(e);
126 int sensor_state_field_number = std::get<1>(e);
127
128 std::string sensor_state_path = sysfs_path + "/" + sensor_path;
129 sensor_state_path += (event_point == PixelAtoms::WaterEventReported::EventPoint::WaterEventReported_EventPoint_BOOT) ? "/boot_value" : "/latched_value";
130
131 int sensor_state;
132 if (!readFileToInt(sensor_state_path, &sensor_state)) {
133 continue;
134 }
135
136 auto &sensor_state_field = values[sensor_state_field_number - kVendorAtomOffset];
137 switch (sensor_state) {
138 case 0:
139 sensor_state_field = PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_DRY;
140 break;
141 case 1:
142 sensor_state_field = PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_WET;
143 break;
144 case 2:
145 sensor_state_field = PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_DISABLED;
146 break;
147 case 3:
148 sensor_state_field = PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_INVALID;
149 break;
150 default:
151 sensor_state_field = PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_SENSOR_STATE_UNKNOWN;
152 }
153 }
154
155 VendorAtom event = {.reverseDomainName = "",
156 .atomId = PixelAtoms::Atom::kWaterEventReported,
157 .values = std::move(values)};
158 const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
159 if (!ret.isOk())
160 ALOGE("Unable to report Water event.");
161 }
162
logBootEvent(const std::shared_ptr<IStats> & stats_client,const std::vector<std::string> & sysfs_roots)163 void WaterEventReporter::logBootEvent(const std::shared_ptr<IStats> &stats_client,
164 const std::vector<std::string> &sysfs_roots)
165 {
166 ALOGD("Reporting at boot");
167 const PixelAtoms::WaterEventReported::EventPoint event_point =
168 PixelAtoms::WaterEventReported::EventPoint::WaterEventReported_EventPoint_BOOT;
169 for (const auto& sysfs_root : sysfs_roots)
170 logEvent(stats_client, event_point, sysfs_root);
171 }
172
logUevent(const std::shared_ptr<IStats> & stats_client,const std::string_view uevent_devpath)173 void WaterEventReporter::logUevent(const std::shared_ptr<IStats> &stats_client,
174 const std::string_view uevent_devpath)
175 {
176 ALOGI("Reporting at uevent");
177 std::string dpath(uevent_devpath);
178
179 std::vector<std::string> value = android::base::Split(dpath, "=");
180 if (value.size() != 2) {
181 ALOGE("Error report Water event split failed");
182 return;
183 }
184
185 std::string sysfs_path("/sys");
186 sysfs_path += value[1];
187
188 PixelAtoms::WaterEventReported::EventPoint event_point =
189 PixelAtoms::WaterEventReported::EventPoint::WaterEventReported_EventPoint_IRQ;
190 logEvent(stats_client, event_point, sysfs_path);
191 }
192
ueventDriverMatch(const char * const driver)193 bool WaterEventReporter::ueventDriverMatch(const char * const driver) {
194 return !strncmp(driver, WATER_EVENT_DRIVER_STR, strlen(WATER_EVENT_DRIVER_STR));
195 }
196
197 } // namespace pixel
198 } // namespace google
199 } // namespace hardware
200 } // namespace android
201