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(kNumOfWaterEventAtoms, 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 std::string fuse_state_str;
88 if (ReadFileToString(sysfs_path + "/fuse/status", &fuse_state_str)) {
89 if (!fuse_state_str.compare(0, 4, "open")) {
90 values[PixelAtoms::WaterEventReported::kFuseStateFieldNumber - kVendorAtomOffset] =
91 PixelAtoms::WaterEventReported::FuseState::WaterEventReported_FuseState_BLOWN;
92 } else if (!fuse_state_str.compare(0, 5, "short")) {
93 values[PixelAtoms::WaterEventReported::kFuseStateFieldNumber - kVendorAtomOffset] =
94 PixelAtoms::WaterEventReported::FuseState::WaterEventReported_FuseState_INTACT;
95 } else {
96 values[PixelAtoms::WaterEventReported::kFuseStateFieldNumber - kVendorAtomOffset] =
97 PixelAtoms::WaterEventReported::FuseState::WaterEventReported_FuseState_FUSE_STATE_UNKNOWN;
98 }
99 }
100
101 // Is the fuse enabled
102 int fuse_enable;
103 if (readFileToInt(sysfs_path + "/fuse/enable", &fuse_enable))
104 values[PixelAtoms::WaterEventReported::kFuseEnabledFieldNumber - kVendorAtomOffset] =
105 fuse_enable ? PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_ENABLED :
106 PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_DISABLED;
107
108 // Is system fault enabled
109 int fault_enable;
110 if (readFileToInt(sysfs_path + "/fault/enable", &fault_enable))
111 values[PixelAtoms::WaterEventReported::kFaultEnabledFieldNumber - kVendorAtomOffset] =
112 fault_enable ? PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_ENABLED :
113 PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_DISABLED;
114
115 std::tuple<std::string, int, int> sensors[] = {
116 {"reference", PixelAtoms::WaterEventReported::kReferenceStateFieldNumber, PixelAtoms::WaterEventReported::kReferenceThresholdFieldNumber},
117 {"sensor0", PixelAtoms::WaterEventReported::kSensor0StateFieldNumber, PixelAtoms::WaterEventReported::kSensor0ThresholdFieldNumber},
118 {"sensor1", PixelAtoms::WaterEventReported::kSensor1StateFieldNumber, PixelAtoms::WaterEventReported::kSensor1ThresholdFieldNumber},
119 {"sensor2", PixelAtoms::WaterEventReported::kSensor1StateFieldNumber, PixelAtoms::WaterEventReported::kSensor1ThresholdFieldNumber}
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 (auto e : sensors) {
125 std::string sensor_path = std::get<0>(e);
126 int sensor_state_field_number = std::get<1>(e);
127 int threshold_field_number = std::get<2>(e);
128
129 std::string sensor_state_path = sysfs_path + "/" + sensor_path;
130 sensor_state_path += (event_point == PixelAtoms::WaterEventReported::EventPoint::WaterEventReported_EventPoint_BOOT) ? "/boot_value" : "/latched_value";
131
132 std::string sensor_state_str;
133 if (!ReadFileToString(sensor_state_path, &sensor_state_str)) {
134 continue;
135 }
136
137 if (!sensor_state_str.compare(0, 3, "dry")) {
138 values[sensor_state_field_number - kVendorAtomOffset] =
139 PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_DRY;
140 } else if (sensor_state_str.compare(0, 3, "wet")) {
141 values[sensor_state_field_number- kVendorAtomOffset] =
142 PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_WET;
143 } else if (!sensor_state_str.compare(0, 3, "invl")) {
144 values[sensor_state_field_number - kVendorAtomOffset] =
145 PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_INVALID;
146 } else if (!sensor_state_str.compare(0, 3, "dis")) {
147 values[sensor_state_field_number - kVendorAtomOffset] =
148 PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_DISABLED;
149 } else {
150 values[sensor_state_field_number - kVendorAtomOffset] =
151 PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_SENSOR_STATE_UNKNOWN;
152 continue;
153 }
154
155 // report the threshold
156 std::string threshold_path = sysfs_path + "/" + sensor_path + "/threshold";
157 int sensor_threshold;
158 if (readFileToInt(threshold_path, &sensor_threshold)) {
159 values[PixelAtoms::WaterEventReported::kReferenceThresholdFieldNumber - kVendorAtomOffset] = sensor_threshold;
160 }
161 }
162
163 VendorAtom event = {.reverseDomainName = "",
164 .atomId = PixelAtoms::Atom::kWaterEventReported,
165 .values = std::move(values)};
166 const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
167 if (!ret.isOk())
168 ALOGE("Unable to report Water event.");
169 }
170
logUevent(const std::shared_ptr<IStats> & stats_client,const std::string_view uevent_devpath)171 void WaterEventReporter::logUevent(const std::shared_ptr<IStats> &stats_client,
172 const std::string_view uevent_devpath)
173 {
174 ALOGI("Reporting Water event");
175 std::string dpath(uevent_devpath);
176
177 std::vector<std::string> value = android::base::Split(dpath, "=");
178 if (value.size() != 2) {
179 ALOGE("Error report Water event split failed");
180 return;
181 }
182
183 std::string sysfs_path("/sys");
184 sysfs_path += value[1];
185
186 PixelAtoms::WaterEventReported::EventPoint event_point =
187 PixelAtoms::WaterEventReported::EventPoint::WaterEventReported_EventPoint_IRQ;
188 logEvent(stats_client, event_point, sysfs_path);
189 }
190
ueventDriverMatch(const char * const driver)191 bool WaterEventReporter::ueventDriverMatch(const char * const driver) {
192 return !strncmp(driver, WATER_EVENT_DRIVER_STR, strlen(WATER_EVENT_DRIVER_STR));
193 }
194
195 } // namespace pixel
196 } // namespace google
197 } // namespace hardware
198 } // namespace android
199