blob: a98c31ce0621bbe2a6c633d153a666c7d2ead6e0 [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "pixelstats: WaterEvent"
#include <aidl/android/frameworks/stats/IStats.h>
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android/binder_manager.h>
#include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
#include <pixelstats/WaterEventReporter.h>
#include <utils/Log.h>
#include <cinttypes>
namespace android {
namespace hardware {
namespace google {
namespace pixel {
using aidl::android::frameworks::stats::IStats;
using aidl::android::frameworks::stats::VendorAtom;
using aidl::android::frameworks::stats::VendorAtomValue;
using android::base::ReadFileToString;
static const char * const WATER_EVENT_DRIVER_STR = "DRIVER=h2omg";
WaterEventReporter::WaterEventReporter() {};
static bool fileExists(const std::string &path) {
struct stat sb;
return stat(path.c_str(), &sb) == 0;
}
static bool readFileToInt(const char *const path, int *val) {
std::string file_contents;
if (!ReadFileToString(path, &file_contents)) {
ALOGE("Unable to read %s - %s", path, strerror(errno));
return false;
} else if (sscanf(file_contents.c_str(), "%d", val) != 1) {
ALOGE("Unable to convert %s to int - %s", path, strerror(errno));
return false;
}
return true;
}
static inline bool readFileToInt(const std::string &path, int *val) {
return readFileToInt(path.c_str(), val);
}
void WaterEventReporter::logEvent(const std::shared_ptr<IStats> &stats_client,
PixelAtoms::WaterEventReported::EventPoint event_point,
const std::string_view sysfs_root)
{
const std::string sysfs_path(sysfs_root);
static int count = 0;
if (!fileExists(sysfs_path)) {
ALOGE("WaterEvent path is not valid %s", sysfs_path.c_str());
return;
}
std::vector<VendorAtomValue> values(kNumOfWaterEventAtomFields, 0);
// Is this during boot or as a result of an event
values[PixelAtoms::WaterEventReported::kCollectionEventFieldNumber - kVendorAtomOffset] = event_point;
// Most important, what is the state of the fuse
int fuse_state;
if (readFileToInt(sysfs_path + "/fuse/status", &fuse_state)) {
auto &fuse_state_field = values[PixelAtoms::WaterEventReported::kFuseStateFieldNumber - kVendorAtomOffset];
switch (fuse_state) {
case 1:
fuse_state_field = PixelAtoms::WaterEventReported::FuseState::WaterEventReported_FuseState_BLOWN;
break;
case 0:
fuse_state_field = PixelAtoms::WaterEventReported::FuseState::WaterEventReported_FuseState_INTACT;
break;
default:
fuse_state_field = PixelAtoms::WaterEventReported::FuseState::WaterEventReported_FuseState_FUSE_STATE_UNKNOWN;
}
}
// Is the fuse enabled
int fuse_enable;
if (readFileToInt(sysfs_path + "/fuse/enable", &fuse_enable))
values[PixelAtoms::WaterEventReported::kFuseEnabledFieldNumber - kVendorAtomOffset] =
fuse_enable ? PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_ENABLED :
PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_DISABLED;
// Is system fault enabled
int fault_enable;
if (readFileToInt(sysfs_path + "/fault/enable", &fault_enable))
values[PixelAtoms::WaterEventReported::kFaultEnabledFieldNumber - kVendorAtomOffset] =
fault_enable ? PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_ENABLED :
PixelAtoms::WaterEventReported::CircuitState::WaterEventReported_CircuitState_CIRCUIT_DISABLED;
const std::tuple<std::string, int> sensors[] = {
{"reference", PixelAtoms::WaterEventReported::kReferenceStateFieldNumber},
{"sensor0", PixelAtoms::WaterEventReported::kSensor0StateFieldNumber},
{"sensor1", PixelAtoms::WaterEventReported::kSensor1StateFieldNumber},
{"sensor2", PixelAtoms::WaterEventReported::kSensor1StateFieldNumber}
};
// Get the sensor states (including reference) from either the boot_value (if this is during
// startup), or the latched_value if this is the result of a uevent
for (const auto& e : sensors) {
const std::string &sensor_path = std::get<0>(e);
int sensor_state_field_number = std::get<1>(e);
std::string sensor_state_path = sysfs_path + "/" + sensor_path;
sensor_state_path += (event_point == PixelAtoms::WaterEventReported::EventPoint::WaterEventReported_EventPoint_BOOT) ? "/boot_value" : "/latched_value";
int sensor_state;
if (!readFileToInt(sensor_state_path, &sensor_state)) {
continue;
}
auto &sensor_state_field = values[sensor_state_field_number - kVendorAtomOffset];
switch (sensor_state) {
case 0:
sensor_state_field = PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_DRY;
break;
case 1:
sensor_state_field = PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_WET;
break;
case 2:
sensor_state_field = PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_DISABLED;
break;
case 3:
sensor_state_field = PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_INVALID;
break;
default:
sensor_state_field = PixelAtoms::WaterEventReported::SensorState::WaterEventReported_SensorState_SENSOR_STATE_UNKNOWN;
}
}
VendorAtom event = {.reverseDomainName = "",
.atomId = PixelAtoms::Atom::kWaterEventReported,
.values = std::move(values)};
const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
if (!ret.isOk())
ALOGE("Unable to report Water event.");
}
void WaterEventReporter::logUevent(const std::shared_ptr<IStats> &stats_client,
const std::string_view uevent_devpath)
{
ALOGI("Reporting Water event");
std::string dpath(uevent_devpath);
std::vector<std::string> value = android::base::Split(dpath, "=");
if (value.size() != 2) {
ALOGE("Error report Water event split failed");
return;
}
std::string sysfs_path("/sys");
sysfs_path += value[1];
PixelAtoms::WaterEventReported::EventPoint event_point =
PixelAtoms::WaterEventReported::EventPoint::WaterEventReported_EventPoint_IRQ;
logEvent(stats_client, event_point, sysfs_path);
}
bool WaterEventReporter::ueventDriverMatch(const char * const driver) {
return !strncmp(driver, WATER_EVENT_DRIVER_STR, strlen(WATER_EVENT_DRIVER_STR));
}
} // namespace pixel
} // namespace google
} // namespace hardware
} // namespace android