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