• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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