diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-02-02 23:58:37 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-02-02 23:58:37 +0000 |
commit | 5508d331c326a9ffd1426a73698413cb7d578665 (patch) | |
tree | 39c8d20886a76130742bb4fdc69749874a21d39e | |
parent | d354261df449fd6148e2b741498a4b32c57bf1a2 (diff) | |
parent | e4127a7e5bb05096c138ae44a035f2bf52fecc2b (diff) | |
download | pixel-simpleperf-release.tar.gz |
Snap for 11400057 from e4127a7e5bb05096c138ae44a035f2bf52fecc2b to simpleperf-releasesimpleperf-release
Change-Id: I9ade56d2e5781f6695c07512c4f29a492284f4ad
67 files changed, 2684 insertions, 899 deletions
diff --git a/battery_mitigation/BatteryMitigation.cpp b/battery_mitigation/BatteryMitigation.cpp index 98419fc5..6aadaa48 100644 --- a/battery_mitigation/BatteryMitigation.cpp +++ b/battery_mitigation/BatteryMitigation.cpp @@ -18,7 +18,8 @@ #include <sstream> -#define MAX_BROWNOUT_DATA_AGE_SECONDS 300 +#define MAX_BROWNOUT_DATA_AGE_MINUTES 5 +#define ONE_SECOND_IN_US 1000000 namespace android { namespace hardware { @@ -48,8 +49,24 @@ bool BatteryMitigation::isMitigationLogTimeValid(std::chrono::system_clock::time std::istringstream ss(pattern_match.str()); ss >> std::get_time(&triggeredTimestamp, timestampFormat); auto logFileTime = std::chrono::system_clock::from_time_t(mktime(&triggeredTimestamp)); - auto delta = std::chrono::duration_cast<std::chrono::seconds>(startTime - logFileTime); - if ((delta.count() < MAX_BROWNOUT_DATA_AGE_SECONDS) && (delta.count() > 0)) { + auto epoch_logFileTime = logFileTime.time_since_epoch().count() / ONE_SECOND_IN_US; + + // Convert start time to same format + auto time_sec = std::chrono::system_clock::to_time_t(startTime); + struct tm start_tm; + std::stringstream oss; + localtime_r(&time_sec, &start_tm); + oss << std::put_time(&start_tm, timestampFormat) << std::flush; + std::tm startTimestamp = {}; + std::istringstream st(oss.str()); + st >> std::get_time(&startTimestamp, timestampFormat); + auto start = std::chrono::system_clock::from_time_t(mktime(&startTimestamp)); + auto epoch_startTime = start.time_since_epoch().count() / ONE_SECOND_IN_US; + + auto delta = epoch_startTime - epoch_logFileTime; + auto delta_minutes = delta / 60; + + if ((delta_minutes < MAX_BROWNOUT_DATA_AGE_MINUTES) && (delta_minutes >= 0)) { return true; } } diff --git a/common/pixel-common-device.mk b/common/pixel-common-device.mk index e9d92957..5df9cda2 100644 --- a/common/pixel-common-device.mk +++ b/common/pixel-common-device.mk @@ -4,10 +4,6 @@ PRODUCT_COPY_FILES += \ BOARD_VENDOR_SEPOLICY_DIRS += hardware/google/pixel-sepolicy/common/vendor SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS += hardware/google/pixel-sepolicy/common/system_ext -# Write flags to the vendor space in /misc partition. -PRODUCT_PACKAGES += \ - misc_writer - # Enable atrace categories and tools for pixel devices PRODUCT_PACKAGES += \ atrace_categories.txt.pixel \ diff --git a/health/Android.bp b/health/Android.bp index 3039431d..3b67e1ec 100644 --- a/health/Android.bp +++ b/health/Android.bp @@ -35,13 +35,13 @@ cc_library { export_shared_lib_headers: [ "android.frameworks.stats-V1-ndk", - "android.hardware.health-V2-ndk", + "android.hardware.health-V3-ndk", "libpixelatoms_defs", ], shared_libs: [ "android.frameworks.stats-V1-ndk", - "android.hardware.health-V2-ndk", + "android.hardware.health-V3-ndk", "libbase", "libbinder_ndk", "libcutils", diff --git a/misc_writer/include/misc_writer/misc_writer.h b/misc_writer/include/misc_writer/misc_writer.h index ce3da5c8..ba1b6857 100644 --- a/misc_writer/include/misc_writer/misc_writer.h +++ b/misc_writer/include/misc_writer/misc_writer.h @@ -61,6 +61,7 @@ class MiscWriter { static constexpr char kTimeOffset[] = "timeoffset="; static constexpr uint32_t kMaxRamSizeOffsetInVendorSpace = 192; static constexpr char kMaxRamSize[] = "max-ram-size="; + static constexpr uint32_t kSotaStateOffsetInVendorSpace = 224; // Minimum and maximum valid value for max-ram-size static constexpr int32_t kRamSizeDefault = -1; diff --git a/misc_writer/misc_writer.cpp b/misc_writer/misc_writer.cpp index 8458649f..216b1883 100644 --- a/misc_writer/misc_writer.cpp +++ b/misc_writer/misc_writer.cpp @@ -16,12 +16,12 @@ #include "misc_writer/misc_writer.h" -#include <string.h> - #include <android-base/file.h> #include <android-base/logging.h> +#include <android-base/properties.h> #include <android-base/stringprintf.h> #include <bootloader_message/bootloader_message.h> +#include <string.h> namespace android { namespace hardware { @@ -103,6 +103,19 @@ bool MiscWriter::PerformAction(std::optional<size_t> override_offset) { LOG(ERROR) << "Failed to write " << content << " at offset " << offset << " : " << err; return false; } + + if (action_ == MiscWriterActions::kSetSotaFlag) { + content = ::android::base::GetProperty("persist.vendor.nfc.factoryota.state", ""); + if (content.size() != 0 && content.size() <= 40) { + offset = kSotaStateOffsetInVendorSpace; + if (std::string err; + !WriteMiscPartitionVendorSpace(content.data(), content.size(), offset, &err)) { + LOG(ERROR) << "Failed to write " << content << " at offset " << offset << " : " << err; + return false; + } + } + } + return true; } diff --git a/misc_writer/misc_writer_test.cpp b/misc_writer/misc_writer_test.cpp index 651f6409..495ff686 100644 --- a/misc_writer/misc_writer_test.cpp +++ b/misc_writer/misc_writer_test.cpp @@ -20,6 +20,7 @@ #include <vector> #include <android-base/file.h> +#include <android-base/properties.h> #include <bootloader_message/bootloader_message.h> #include <gtest/gtest.h> @@ -95,6 +96,10 @@ TEST_F(MiscWriterTest, SetClearSota) { std::string expected = "enable-sota"; CheckMiscPartitionVendorSpaceContent(32, expected); + expected = ::android::base::GetProperty("persist.vendor.nfc.factoryota.state", ""); + if (expected.size() != 0 && expected.size() <= 40) + CheckMiscPartitionVendorSpaceContent(224, expected); + // Test we can write to the override offset. size_t override_offset = 12360; ASSERT_FALSE(misc_writer_->PerformAction(override_offset)); diff --git a/pixelstats/Android.bp b/pixelstats/Android.bp index f22a15f1..a0e55a36 100644 --- a/pixelstats/Android.bp +++ b/pixelstats/Android.bp @@ -149,9 +149,11 @@ cc_library { "BatteryHealthReporter.cpp", "BrownoutDetectedReporter.cpp", "ChargeStatsReporter.cpp", + "DisplayStatsReporter.cpp", "DropDetect.cpp", "MmMetricsReporter.cpp", "MitigationStatsReporter.cpp", + "MitigationDurationReporter.cpp", "PcaChargeStats.cpp", "StatsHelper.cpp", "SysfsCollector.cpp", @@ -186,3 +188,10 @@ cc_library { ], header_libs: ["chre_api"], } + +filegroup { + name: "pixelatoms_proto", + srcs: [ + "pixelatoms.proto", + ], +} diff --git a/pixelstats/BrownoutDetectedReporter.cpp b/pixelstats/BrownoutDetectedReporter.cpp index 58edc995..e22d2df7 100644 --- a/pixelstats/BrownoutDetectedReporter.cpp +++ b/pixelstats/BrownoutDetectedReporter.cpp @@ -47,6 +47,7 @@ using android::hardware::google::pixel::PixelAtoms::BrownoutDetected; #define DEFAULT_BATTERY_TEMP 9999999 #define DEFAULT_BATTERY_SOC 100 #define DEFAULT_BATTERY_VOLT 5000000 +#define ONE_SECOND_IN_US 1000000 const std::regex kTimestampPattern("^\\S+\\s[0-9]+:[0-9]+:[0-9]+\\S+$"); const std::regex kIrqPattern("^(\\S+)\\striggered\\sat\\s\\S+$"); @@ -212,7 +213,7 @@ long BrownoutDetectedReporter::parseTimestamp(std::string timestamp) { std::string timestampFormat = "%Y-%m-%d %H:%M:%S"; if (strptime(timestamp.substr(0, 19).c_str(), timestampFormat.c_str(), &triggeredTimestamp)) { auto logFileTime = std::chrono::system_clock::from_time_t(mktime(&triggeredTimestamp)); - return logFileTime.time_since_epoch().count(); + return logFileTime.time_since_epoch().count() / ONE_SECOND_IN_US; } return 0; } diff --git a/pixelstats/ChargeStatsReporter.cpp b/pixelstats/ChargeStatsReporter.cpp index e3727b85..2354acd4 100644 --- a/pixelstats/ChargeStatsReporter.cpp +++ b/pixelstats/ChargeStatsReporter.cpp @@ -117,6 +117,8 @@ void ChargeStatsReporter::ReportChargeStats(const std::shared_ptr<IStats> &stats tmp[12] = pca_rs[4]; tmp[14] = pca_rs[1]; if (wline_at.empty()) { + /* force adapter type to PPS when pca log is available, but not wlc */ + tmp[0] = PixelAtoms::ChargeStats::ADAPTER_TYPE_USB_PD_PPS; tmp[8] = pca_ac[0]; tmp[9] = pca_ac[1]; tmp[13] = pca_rs[0]; diff --git a/pixelstats/DisplayStatsReporter.cpp b/pixelstats/DisplayStatsReporter.cpp new file mode 100644 index 00000000..3aff2225 --- /dev/null +++ b/pixelstats/DisplayStatsReporter.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2023 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: DisplayStats" + +#include <aidl/android/frameworks/stats/IStats.h> +#include <android-base/file.h> +#include <android-base/parseint.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/DisplayStatsReporter.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; +using android::hardware::google::pixel::PixelAtoms::DisplayPanelErrorStats; + +DisplayStatsReporter::DisplayStatsReporter() {} + +bool DisplayStatsReporter::readDisplayPanelErrorCount(const std::string &path, int64_t *val) { + std::string file_contents; + + if (path.empty()) { + return false; + } + + if (!ReadFileToString(path.c_str(), &file_contents)) { + if (errno != ENOENT) { + ALOGD("readDisplayPanelErrorCount Unable to read %s - %s", path.c_str(), + strerror(errno)); + } + return false; + } else { + file_contents = android::base::Trim(file_contents); + if (!android::base::ParseInt(file_contents, val)) { + return false; + } + } + + return true; +} + +bool DisplayStatsReporter::captureDisplayPanelErrorStats( + const std::vector<std::string> &display_stats_paths, + struct DisplayPanelErrorStats *pcur_data) { + bool report_stats = false; + std::string path; + + if (display_stats_paths.size() < kNumOfDisplayPanelErrorStats) { + ALOGE("Number of display stats paths (%zu) is less than expected (%d)", + display_stats_paths.size(), kNumOfDisplayPanelErrorStats); + return false; + } + + int64_t index = PixelAtoms::DisplayPanelErrorStats::kPrimaryErrorCountTeFieldNumber; + index = index - kVendorAtomOffset; + path = display_stats_paths[index]; + + // Read primary panel error stats. + if (!readDisplayPanelErrorCount(path, &(pcur_data->primary_error_count_te))) { + pcur_data->primary_error_count_te = prev_data_.primary_error_count_te; + } else { + report_stats |= (pcur_data->primary_error_count_te > prev_data_.primary_error_count_te); + } + + index = PixelAtoms::DisplayPanelErrorStats::kPrimaryErrorCountUnknownFieldNumber; + index = index - kVendorAtomOffset; + path = display_stats_paths[index]; + if (!readDisplayPanelErrorCount(path, &(pcur_data->primary_error_count_unknown))) { + pcur_data->primary_error_count_unknown = prev_data_.primary_error_count_unknown; + } else { + report_stats |= + (pcur_data->primary_error_count_unknown > prev_data_.primary_error_count_unknown); + } + + // Read secondary panel error stats. + index = PixelAtoms::DisplayPanelErrorStats::kSecondaryErrorCountTeFieldNumber; + index = index - kVendorAtomOffset; + path = display_stats_paths[index]; + if (!readDisplayPanelErrorCount(path, &(pcur_data->secondary_error_count_te))) { + pcur_data->secondary_error_count_te = prev_data_.secondary_error_count_te; + } else { + report_stats |= (pcur_data->secondary_error_count_te > prev_data_.secondary_error_count_te); + } + + index = PixelAtoms::DisplayPanelErrorStats::kSecondaryErrorCountUnknownFieldNumber; + index = index - kVendorAtomOffset; + path = display_stats_paths[index]; + if (!readDisplayPanelErrorCount(path, &(pcur_data->secondary_error_count_unknown))) { + pcur_data->secondary_error_count_unknown = prev_data_.secondary_error_count_unknown; + } else { + report_stats |= (pcur_data->secondary_error_count_unknown > + prev_data_.secondary_error_count_unknown); + } + + return report_stats; +} + +void DisplayStatsReporter::logDisplayPanelErrorStats( + const std::shared_ptr<IStats> &stats_client, + const std::vector<std::string> &display_stats_paths) { + struct DisplayPanelErrorStats cur_data = prev_data_; + + if (!captureDisplayPanelErrorStats(display_stats_paths, &cur_data)) { + prev_data_ = cur_data; + return; + } + + VendorAtomValue tmp; + int64_t max_error_count = static_cast<int64_t>(INT32_MAX); + int error_count; + std::vector<VendorAtomValue> values(kNumOfDisplayPanelErrorStats); + + error_count = std::min<int64_t>( + cur_data.primary_error_count_te - prev_data_.primary_error_count_te, max_error_count); + tmp.set<VendorAtomValue::intValue>(error_count); + int64_t index = PixelAtoms::DisplayPanelErrorStats::kPrimaryErrorCountTeFieldNumber; + index = index - kVendorAtomOffset; + values[index] = tmp; + + error_count = std::min<int64_t>( + cur_data.primary_error_count_unknown - prev_data_.primary_error_count_unknown, + max_error_count); + tmp.set<VendorAtomValue::intValue>(error_count); + index = PixelAtoms::DisplayPanelErrorStats::kPrimaryErrorCountUnknownFieldNumber; + index = index - kVendorAtomOffset; + values[index] = tmp; + + prev_data_ = cur_data; + + ALOGD("Report updated display panel metrics to stats service"); + // Send vendor atom to IStats HAL + VendorAtom event = {.reverseDomainName = "", + .atomId = PixelAtoms::Atom::kDisplayPanelErrorStats, + .values = std::move(values)}; + const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event); + if (!ret.isOk()) + ALOGE("Unable to report display Display Panel stats to Stats service"); +} + +void DisplayStatsReporter::logDisplayStats(const std::shared_ptr<IStats> &stats_client, + const std::vector<std::string> &display_stats_paths) { + logDisplayPanelErrorStats(stats_client, display_stats_paths); +} + +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android diff --git a/pixelstats/MitigationDurationReporter.cpp b/pixelstats/MitigationDurationReporter.cpp new file mode 100644 index 00000000..b9518f63 --- /dev/null +++ b/pixelstats/MitigationDurationReporter.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2023 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: PowerMitigationDurationCounts" + +#include <aidl/android/frameworks/stats/IStats.h> +#include <android-base/file.h> +#include <android-base/parseint.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/MitigationDurationReporter.h> +#include <utils/Log.h> + +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; +using android::hardware::google::pixel::PixelAtoms::PowerMitigationDurationCounts; + +enum DurationOutputOrder { + UVLO1, + UVLO1_MMWAVE, + UVLO1_RFFE, + UVLO2, + UVLO2_MMWAVE, + UVLO2_RFFE, + BATOILO, + BATOILO_MMWAVE, + BATOILO_RFFE, + MAIN0, + MAIN1, + MAIN2, + MAIN3, + MAIN4, + MAIN5, + MAIN6, + MAIN7, + MAIN8, + MAIN9, + MAIN10, + MAIN11, + SUB0, + SUB1, + SUB2, + SUB3, + SUB4, + SUB5, + SUB6, + SUB7, + SUB8, + SUB9, + SUB10, + SUB11, +}; + +MitigationDurationReporter::MitigationDurationReporter() {} + +bool MitigationDurationReporter::getStatFromLine(const std::string *line, int *val) { + std::vector<std::string> strs = android::base::Split(*line, ":"); + if (strs.size() != 2) { + ALOGI("Unable to split %s", line->c_str()); + return false; + } + std::string str = strs[1]; + str = android::base::Trim(str); + str.erase(std::remove(str.begin(), str.end(), '\n'), str.cend()); + if (!android::base::ParseInt(str, val)) { + ALOGI("Unable to convert %s to int - %s", str.c_str(), strerror(errno)); + return false; + } + return true; +} + +void MitigationDurationReporter::valueAssignmentHelper(std::vector<VendorAtomValue> *values, + int *val, int fieldNumber) { + VendorAtomValue tmp; + tmp.set<VendorAtomValue::intValue>(*val); + (*values)[fieldNumber - kVendorAtomOffset] = tmp; +} + +void MitigationDurationReporter::logMitigationDuration(const std::shared_ptr<IStats> &stats_client, + const std::string &path) { + struct IrqDurationCounts greater_than_thresh = {}; + + if (!getIrqDurationCountHelper(path + kGreaterThanTenMsSysfsNode, &greater_than_thresh)) + return; + + VendorAtomValue tmp; + std::vector<VendorAtomValue> values(33); + + valueAssignmentHelper(&values, &greater_than_thresh.uvlo1_none, + PowerMitigationDurationCounts::kGreaterThanThreshUvlo1NoneFieldNumber); + valueAssignmentHelper(&values, &greater_than_thresh.uvlo1_mmwave, + PowerMitigationDurationCounts::kGreaterThanThreshUvlo1MmwaveFieldNumber); + valueAssignmentHelper(&values, &greater_than_thresh.uvlo1_rffe, + PowerMitigationDurationCounts::kGreaterThanThreshUvlo1RffeFieldNumber); + + valueAssignmentHelper(&values, &greater_than_thresh.uvlo2_none, + PowerMitigationDurationCounts::kGreaterThanThreshUvlo2NoneFieldNumber); + valueAssignmentHelper(&values, &greater_than_thresh.uvlo2_mmwave, + PowerMitigationDurationCounts::kGreaterThanThreshUvlo2MmwaveFieldNumber); + valueAssignmentHelper(&values, &greater_than_thresh.uvlo2_rffe, + PowerMitigationDurationCounts::kGreaterThanThreshUvlo2RffeFieldNumber); + + valueAssignmentHelper(&values, &greater_than_thresh.batoilo_none, + PowerMitigationDurationCounts::kGreaterThanThreshBatoiloNoneFieldNumber); + valueAssignmentHelper( + &values, &greater_than_thresh.batoilo_mmwave, + PowerMitigationDurationCounts::kGreaterThanThreshBatoiloMmwaveFieldNumber); + valueAssignmentHelper(&values, &greater_than_thresh.batoilo_rffe, + PowerMitigationDurationCounts::kGreaterThanThreshBatoiloRffeFieldNumber); + + int i; + for (i = 0; i < MITIGATION_DURATION_MAIN_COUNT; i++) { + valueAssignmentHelper( + &values, &greater_than_thresh.main[i], + PowerMitigationDurationCounts::kGreaterThanThreshMain0FieldNumber + i); + } + + for (i = 0; i < MITIGATION_DURATION_SUB_COUNT; i++) { + valueAssignmentHelper(&values, &greater_than_thresh.sub[i], + PowerMitigationDurationCounts::kGreaterThanThreshSub0FieldNumber + i); + } + + // Send vendor atom to IStats HAL + VendorAtom event = {.reverseDomainName = "", + .atomId = PixelAtoms::Atom::kMitigationDuration, + .values = std::move(values)}; + const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event); + if (!ret.isOk()) + ALOGE("Unable to report to Stats service"); +} + +int MitigationDurationReporter::updateStat(const std::string *line, int *val) { + int stat_value; + if (!getStatFromLine(line, &stat_value) || *val == stat_value) { + return 0; + } + + *val = stat_value; + return 1; +} + +bool MitigationDurationReporter::getIrqDurationCountHelper( + const std::string kMitigationDurationFile, struct IrqDurationCounts *counts) { + std::string file_contents; + + if (!ReadFileToString(kMitigationDurationFile, &file_contents)) { + ALOGI("Unable to read %s - %s", kMitigationDurationFile.c_str(), strerror(errno)); + return false; + } + + std::vector<std::string> lines = android::base::Split(file_contents, "\n"); + if (lines.size() < kExpectedNumberOfLines) { + ALOGI("Readback size is invalid"); + return false; + } + + int16_t i; + int num_stats = 0; + + num_stats += updateStat(&lines[UVLO1], &counts->uvlo1_none); + num_stats += updateStat(&lines[UVLO1_MMWAVE], &counts->uvlo1_mmwave); + num_stats += updateStat(&lines[UVLO1_RFFE], &counts->uvlo1_rffe); + num_stats += updateStat(&lines[UVLO2], &counts->uvlo2_none); + num_stats += updateStat(&lines[UVLO2_MMWAVE], &counts->uvlo2_mmwave); + num_stats += updateStat(&lines[UVLO2_RFFE], &counts->uvlo2_rffe); + num_stats += updateStat(&lines[BATOILO], &counts->batoilo_none); + num_stats += updateStat(&lines[BATOILO_MMWAVE], &counts->batoilo_mmwave); + num_stats += updateStat(&lines[BATOILO_RFFE], &counts->batoilo_rffe); + + for (i = MAIN0; i <= MAIN11; i++) { + num_stats += updateStat(&lines[i], &counts->main[i - MAIN0]); + } + + for (i = SUB0; i <= SUB11; i++) { + num_stats += updateStat(&lines[i], &counts->sub[i - SUB0]); + } + + return num_stats > 0; +} + +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android diff --git a/pixelstats/SysfsCollector.cpp b/pixelstats/SysfsCollector.cpp index f4cef9bf..4460ca1c 100644 --- a/pixelstats/SysfsCollector.cpp +++ b/pixelstats/SysfsCollector.cpp @@ -50,6 +50,7 @@ using android::base::WriteStringToFile; using android::hardware::google::pixel::PixelAtoms::BatteryCapacity; using android::hardware::google::pixel::PixelAtoms::BlockStatsReported; using android::hardware::google::pixel::PixelAtoms::BootStatsInfo; +using android::hardware::google::pixel::PixelAtoms::DisplayPanelErrorStats; using android::hardware::google::pixel::PixelAtoms::F2fsAtomicWriteInfo; using android::hardware::google::pixel::PixelAtoms::F2fsCompressionInfo; using android::hardware::google::pixel::PixelAtoms::F2fsGcSegmentInfo; @@ -60,7 +61,11 @@ using android::hardware::google::pixel::PixelAtoms::PcieLinkStatsReported; using android::hardware::google::pixel::PixelAtoms::StorageUfsHealth; using android::hardware::google::pixel::PixelAtoms::StorageUfsResetCount; using android::hardware::google::pixel::PixelAtoms::ThermalDfsStats; +using android::hardware::google::pixel::PixelAtoms::VendorAudioAdaptedInfoStatsReported; using android::hardware::google::pixel::PixelAtoms::VendorAudioHardwareStatsReported; +using android::hardware::google::pixel::PixelAtoms::VendorAudioPcmStatsReported; +using android::hardware::google::pixel::PixelAtoms::VendorAudioPdmStatsReported; +using android::hardware::google::pixel::PixelAtoms::VendorAudioThirdPartyEffectStatsReported; using android::hardware::google::pixel::PixelAtoms::VendorChargeCycles; using android::hardware::google::pixel::PixelAtoms::VendorHardwareFailed; using android::hardware::google::pixel::PixelAtoms::VendorLongIRQStatsReported; @@ -95,6 +100,7 @@ SysfsCollector::SysfsCollector(const struct SysfsPaths &sysfs_paths) kBrownoutLogPath(sysfs_paths.BrownoutLogPath), kBrownoutReasonProp(sysfs_paths.BrownoutReasonProp), kPowerMitigationStatsPath(sysfs_paths.MitigationPath), + kPowerMitigationDurationPath(sysfs_paths.MitigationDurationPath), kSpeakerTemperaturePath(sysfs_paths.SpeakerTemperaturePath), kSpeakerExcursionPath(sysfs_paths.SpeakerExcursionPath), kSpeakerHeartbeatPath(sysfs_paths.SpeakerHeartBeatPath), @@ -105,9 +111,19 @@ SysfsCollector::SysfsCollector(const struct SysfsPaths &sysfs_paths) kCCARatePath(sysfs_paths.CCARatePath), kTempResidencyAndResetPaths(sysfs_paths.TempResidencyAndResetPaths), kLongIRQMetricsPath(sysfs_paths.LongIRQMetricsPath), + kStormIRQMetricsPath(sysfs_paths.StormIRQMetricsPath), + kIRQStatsResetPath(sysfs_paths.IRQStatsResetPath), kResumeLatencyMetricsPath(sysfs_paths.ResumeLatencyMetricsPath), kModemPcieLinkStatsPath(sysfs_paths.ModemPcieLinkStatsPath), - kWifiPcieLinkStatsPath(sysfs_paths.WifiPcieLinkStatsPath) {} + kWifiPcieLinkStatsPath(sysfs_paths.WifiPcieLinkStatsPath), + kDisplayStatsPaths(sysfs_paths.DisplayStatsPaths), + kPDMStatePath(sysfs_paths.PDMStatePath), + kWavesPath(sysfs_paths.WavesPath), + kAdaptedInfoCountPath(sysfs_paths.AdaptedInfoCountPath), + kAdaptedInfoDurationPath(sysfs_paths.AdaptedInfoDurationPath), + kPcmLatencyPath(sysfs_paths.PcmLatencyPath), + kPcmCountPath(sysfs_paths.PcmCountPath), + kTotalCallCountPath(sysfs_paths.TotalCallCountPath) {} bool SysfsCollector::ReadFileToInt(const std::string &path, int *val) { return ReadFileToInt(path.c_str(), val); @@ -385,6 +401,10 @@ void SysfsCollector::logSpeakerHealthStats(const std::shared_ptr<IStats> &stats_ } } +void SysfsCollector::logDisplayStats(const std::shared_ptr<IStats> &stats_client) { + display_stats_reporter_.logDisplayStats(stats_client, kDisplayStatsPaths); +} + void SysfsCollector::logThermalStats(const std::shared_ptr<IStats> &stats_client) { thermal_stats_reporter_.logThermalStats(stats_client, kThermalStatsPaths); } @@ -1064,7 +1084,8 @@ void SysfsCollector::logBootStats(const std::shared_ptr<IStats> &stats_client) { */ void SysfsCollector::logVendorAudioHardwareStats(const std::shared_ptr<IStats> &stats_client) { std::string file_contents; - uint32_t milli_ams_rate, cca_active_rate, cca_enable_rate; + uint32_t milli_ams_rate, c1, c2, c3, c4; + uint32_t total_call_voice = 0, total_call_voip = 0; bool isAmsReady = false, isCCAReady = false; if (kAmsRatePath == nullptr) { @@ -1088,12 +1109,22 @@ void SysfsCollector::logVendorAudioHardwareStats(const std::shared_ptr<IStats> & if (!ReadFileToString(kCCARatePath, &file_contents)) { ALOGD("Unable to read cca_rate path %s", kCCARatePath); } else { - if (sscanf(file_contents.c_str(), "%u,%u", &cca_active_rate, &cca_enable_rate) != 2) { + if (sscanf(file_contents.c_str(), "%u %u %u %u", &c1, &c2, &c3, &c4) != 4) { ALOGD("Unable to parse cca rates %s", file_contents.c_str()); } else { isCCAReady = true; - ALOGD("cca_active_rate = %u, cca_enable_rate = %u", cca_active_rate, - cca_enable_rate); + } + } + } + + if (kTotalCallCountPath == nullptr) { + ALOGD("Total call count path not specified"); + } else { + if (!ReadFileToString(kTotalCallCountPath, &file_contents)) { + ALOGD("Unable to read total call path %s", kTotalCallCountPath); + } else { + if (sscanf(file_contents.c_str(), "%u %u", &total_call_voice, &total_call_voip) != 2) { + ALOGD("Unable to parse total call %s", file_contents.c_str()); } } } @@ -1103,33 +1134,392 @@ void SysfsCollector::logVendorAudioHardwareStats(const std::shared_ptr<IStats> & return; } - std::vector<VendorAtomValue> values(3); - VendorAtomValue tmp; + // Sending ams_rate, total_call, c1 and c2 + { + std::vector<VendorAtomValue> values(7); + VendorAtomValue tmp; + + if (isAmsReady) { + tmp.set<VendorAtomValue::intValue>(milli_ams_rate); + values[VendorAudioHardwareStatsReported::kMilliRateOfAmsPerDayFieldNumber - + kVendorAtomOffset] = tmp; + } + + tmp.set<VendorAtomValue::intValue>(1); + values[VendorAudioHardwareStatsReported::kSourceFieldNumber - kVendorAtomOffset] = tmp; - if (isAmsReady) { - tmp.set<VendorAtomValue::intValue>(milli_ams_rate); - values[VendorAudioHardwareStatsReported::kMilliRateOfAmsPerDayFieldNumber - + if (isCCAReady) { + tmp.set<VendorAtomValue::intValue>(c1); + values[VendorAudioHardwareStatsReported::kCcaActiveCountPerDayFieldNumber - + kVendorAtomOffset] = tmp; + + tmp.set<VendorAtomValue::intValue>(c2); + values[VendorAudioHardwareStatsReported::kCcaEnableCountPerDayFieldNumber - + kVendorAtomOffset] = tmp; + } + + tmp.set<VendorAtomValue::intValue>(total_call_voice); + values[VendorAudioHardwareStatsReported::kTotalCallCountPerDayFieldNumber - kVendorAtomOffset] = tmp; + + // Send vendor atom to IStats HAL + VendorAtom event = {.reverseDomainName = "", + .atomId = PixelAtoms::Atom::kVendorAudioHardwareStatsReported, + .values = std::move(values)}; + const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event); + if (!ret.isOk()) + ALOGE("Unable to report VendorAudioHardwareStatsReported to Stats service"); + } + + // Sending total_call, c3 and c4 + { + std::vector<VendorAtomValue> values(7); + VendorAtomValue tmp; + + tmp.set<VendorAtomValue::intValue>(0); + values[VendorAudioHardwareStatsReported::kSourceFieldNumber - kVendorAtomOffset] = tmp; + + if (isCCAReady) { + tmp.set<VendorAtomValue::intValue>(c3); + values[VendorAudioHardwareStatsReported::kCcaActiveCountPerDayFieldNumber - + kVendorAtomOffset] = tmp; + + tmp.set<VendorAtomValue::intValue>(c4); + values[VendorAudioHardwareStatsReported::kCcaEnableCountPerDayFieldNumber - + kVendorAtomOffset] = tmp; + } + + tmp.set<VendorAtomValue::intValue>(total_call_voip); + values[VendorAudioHardwareStatsReported::kTotalCallCountPerDayFieldNumber - + kVendorAtomOffset] = tmp; + + // Send vendor atom to IStats HAL + VendorAtom event = {.reverseDomainName = "", + .atomId = PixelAtoms::Atom::kVendorAudioHardwareStatsReported, + .values = std::move(values)}; + const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event); + if (!ret.isOk()) + ALOGE("Unable to report VendorAudioHardwareStatsReported to Stats service"); + } +} + +/** + * Report PDM States which indicates microphone background noise level. + * This function will report at most 4 atoms showing different background noise type. + */ +void SysfsCollector::logVendorAudioPdmStatsReported(const std::shared_ptr<IStats> &stats_client) { + std::string file_contents; + std::vector<int> pdm_states; + + if (kPDMStatePath == nullptr) { + ALOGD("Audio PDM State path not specified"); + } else { + if (!ReadFileToString(kPDMStatePath, &file_contents)) { + ALOGD("Unable to read PDM State path %s", kPDMStatePath); + } else { + std::stringstream file_content_stream(file_contents); + while (file_content_stream.good()) { + std::string substr; + int state; + getline(file_content_stream, substr, ','); + if (sscanf(substr.c_str(), "%d", &state) != 1) { + ALOGD("Unable to parse PDM State %s", file_contents.c_str()); + } else { + pdm_states.push_back(state); + ALOGD("Parsed PDM State: %d", state); + } + } + } + } + if (pdm_states.empty()) { + ALOGD("Empty PDM State parsed."); + return; + } + + if (pdm_states.size() > 4) { + ALOGD("Too many values parsed."); + return; + } + + for (int index = 0; index < pdm_states.size(); index++) { + std::vector<VendorAtomValue> values(2); + VendorAtomValue tmp; + + if (pdm_states[index] == 0) { + continue; + } + + tmp.set<VendorAtomValue::intValue>(index); + values[VendorAudioPdmStatsReported::kPdmIndexFieldNumber - kVendorAtomOffset] = tmp; + + tmp.set<VendorAtomValue::intValue>(pdm_states[index]); + values[VendorAudioPdmStatsReported::kStateFieldNumber - kVendorAtomOffset] = tmp; + + // Send vendor atom to IStats HAL + VendorAtom event = {.reverseDomainName = "", + .atomId = PixelAtoms::Atom::kVendorAudioPdmStatsReported, + .values = std::move(values)}; + + const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event); + if (!ret.isOk()) + ALOGE("Unable to report VendorAudioPdmStatsReported at index %d", index); + } +} + +/** + * Report Third party audio effects stats. + * This function will report at most 5 atoms showing different instance stats. + */ +void SysfsCollector::logWavesStats(const std::shared_ptr<IStats> &stats_client) { + std::string file_contents; + std::vector<std::vector<int>> volume_duration_per_instance; + + constexpr int num_instances = 5; + constexpr int num_volume = 10; + + if (kWavesPath == nullptr) { + ALOGD("Audio Waves stats path not specified"); + return; + } + + if (!ReadFileToString(kWavesPath, &file_contents)) { + ALOGD("Unable to read Wave stats path %s", kWavesPath); + } else { + std::stringstream file_content_stream(file_contents); + int duration; + std::vector<int> volume_duration; + while (file_content_stream.good() && file_content_stream >> duration) { + volume_duration.push_back(duration); + if (volume_duration.size() >= num_volume) { + volume_duration_per_instance.push_back(volume_duration); + volume_duration.clear(); + } + } + } + + if (volume_duration_per_instance.size() != num_instances) { + ALOGE("Number of instances %zu doesn't match the correct number %d", + volume_duration_per_instance.size(), num_instances); + return; + } + for (int i = 0; i < volume_duration_per_instance.size(); i++) { + if (volume_duration_per_instance[i].size() != num_volume) { + ALOGE("Number of volume %zu doesn't match the correct number %d", + volume_duration_per_instance[i].size(), num_volume); + return; + } + } + + std::vector<int> volume_range_field_numbers = { + VendorAudioThirdPartyEffectStatsReported::kVolumeRange0ActiveMsPerDayFieldNumber, + VendorAudioThirdPartyEffectStatsReported::kVolumeRange1ActiveMsPerDayFieldNumber, + VendorAudioThirdPartyEffectStatsReported::kVolumeRange2ActiveMsPerDayFieldNumber, + VendorAudioThirdPartyEffectStatsReported::kVolumeRange3ActiveMsPerDayFieldNumber, + VendorAudioThirdPartyEffectStatsReported::kVolumeRange4ActiveMsPerDayFieldNumber, + VendorAudioThirdPartyEffectStatsReported::kVolumeRange5ActiveMsPerDayFieldNumber, + VendorAudioThirdPartyEffectStatsReported::kVolumeRange6ActiveMsPerDayFieldNumber, + VendorAudioThirdPartyEffectStatsReported::kVolumeRange7ActiveMsPerDayFieldNumber, + VendorAudioThirdPartyEffectStatsReported::kVolumeRange8ActiveMsPerDayFieldNumber, + VendorAudioThirdPartyEffectStatsReported::kVolumeRange9ActiveMsPerDayFieldNumber}; + + for (int index = 0; index < volume_duration_per_instance.size(); index++) { + std::vector<VendorAtomValue> values(11); + VendorAtomValue tmp; + + bool has_value = false; + for (int volume_index = 0; volume_index < num_volume; volume_index++) { + if (volume_duration_per_instance[index][volume_index] > 0) { + has_value = true; + } + } + if (!has_value) { + continue; + } + + tmp.set<VendorAtomValue::intValue>(index); + values[VendorAudioThirdPartyEffectStatsReported::kInstanceFieldNumber - kVendorAtomOffset] = + tmp; + + for (int volume_index = 0; volume_index < num_volume; volume_index++) { + tmp.set<VendorAtomValue::intValue>(volume_duration_per_instance[index][volume_index]); + values[volume_range_field_numbers[volume_index] - kVendorAtomOffset] = tmp; + } + // Send vendor atom to IStats HAL + VendorAtom event = {.reverseDomainName = "", + .atomId = PixelAtoms::Atom::kVendorAudioThirdPartyEffectStatsReported, + .values = std::move(values)}; + + const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event); + if (!ret.isOk()) + ALOGE("Unable to report VendorAudioThirdPartyEffectStatsReported at index %d", index); + } +} + +/** + * Report Audio Adapted Information stats such as thermal throttling. + * This function will report at most 6 atoms showing different instance stats. + */ +void SysfsCollector::logAdaptedInfoStats(const std::shared_ptr<IStats> &stats_client) { + std::string file_contents; + std::vector<int> count_per_feature; + std::vector<int> duration_per_feature; + + constexpr int num_features = 6; + + if (kAdaptedInfoCountPath == nullptr) { + ALOGD("Audio Adapted Info Count stats path not specified"); + return; + } + + if (kAdaptedInfoDurationPath == nullptr) { + ALOGD("Audio Adapted Info Duration stats path not specified"); + return; + } + + if (!ReadFileToString(kAdaptedInfoCountPath, &file_contents)) { + ALOGD("Unable to read Adapted Info Count stats path %s", kAdaptedInfoCountPath); + } else { + std::stringstream file_content_stream(file_contents); + int count; + while (file_content_stream.good() && file_content_stream >> count) { + count_per_feature.push_back(count); + } } - if (isCCAReady) { - tmp.set<VendorAtomValue::intValue>(cca_active_rate); - values[VendorAudioHardwareStatsReported::kRateOfCcaActivePerDayFieldNumber - + if (count_per_feature.size() != num_features) { + ALOGD("Audio Adapted Info Count doesn't match the number of features. %zu / %d", + count_per_feature.size(), num_features); + return; + } + + if (!ReadFileToString(kAdaptedInfoDurationPath, &file_contents)) { + ALOGD("Unable to read Adapted Info Duration stats path %s", kAdaptedInfoDurationPath); + } else { + std::stringstream file_content_stream(file_contents); + int duration; + while (file_content_stream.good() && file_content_stream >> duration) { + duration_per_feature.push_back(duration); + } + } + + if (duration_per_feature.size() != num_features) { + ALOGD("Audio Adapted Info Duration doesn't match the number of features. %zu / %d", + duration_per_feature.size(), num_features); + return; + } + + for (int index = 0; index < num_features; index++) { + std::vector<VendorAtomValue> values(3); + VendorAtomValue tmp; + + if (count_per_feature[index] == 0 && duration_per_feature[index] == 0) { + continue; + } + + tmp.set<VendorAtomValue::intValue>(index); + values[VendorAudioAdaptedInfoStatsReported::kFeatureIdFieldNumber - kVendorAtomOffset] = + tmp; + + tmp.set<VendorAtomValue::intValue>(count_per_feature[index]); + values[VendorAudioAdaptedInfoStatsReported::kActiveCountsPerDayFieldNumber - kVendorAtomOffset] = tmp; - tmp.set<VendorAtomValue::intValue>(cca_enable_rate); - values[VendorAudioHardwareStatsReported::kRateOfCcaEnablePerDayFieldNumber - + tmp.set<VendorAtomValue::intValue>(duration_per_feature[index]); + values[VendorAudioAdaptedInfoStatsReported::kActiveDurationMsPerDayFieldNumber - kVendorAtomOffset] = tmp; + + // Send vendor atom to IStats HAL + VendorAtom event = {.reverseDomainName = "", + .atomId = PixelAtoms::Atom::kVendorAudioAdaptedInfoStatsReported, + .values = std::move(values)}; + + const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event); + if (!ret.isOk()) + ALOGE("Unable to report VendorAudioAdaptedInfoStatsReported at index %d", index); } +} - // Send vendor atom to IStats HAL - VendorAtom event = {.reverseDomainName = "", - .atomId = PixelAtoms::Atom::kVendorAudioHardwareStatsReported, - .values = std::move(values)}; +/** + * Report audio PCM usage stats such as latency and active count. + * This function will report at most 19 atoms showing different PCM type. + */ +void SysfsCollector::logPcmUsageStats(const std::shared_ptr<IStats> &stats_client) { + std::string file_contents; + std::vector<int> count_per_type; + std::vector<int> latency_per_type; - const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event); - if (!ret.isOk()) - ALOGE("Unable to report VendorAudioHardwareStatsReported to Stats service"); + constexpr int num_type = 19; + + if (kPcmLatencyPath == nullptr) { + ALOGD("PCM Latency path not specified"); + return; + } + + if (kPcmCountPath == nullptr) { + ALOGD("PCM Count path not specified"); + return; + } + + if (!ReadFileToString(kPcmCountPath, &file_contents)) { + ALOGD("Unable to read PCM Count path %s", kPcmCountPath); + } else { + std::stringstream file_content_stream(file_contents); + int count; + while (file_content_stream.good() && file_content_stream >> count) { + count_per_type.push_back(count); + } + } + + if (count_per_type.size() != num_type) { + ALOGD("Audio PCM Count path doesn't match the number of features. %zu / %d", + count_per_type.size(), num_type); + return; + } + + if (!ReadFileToString(kPcmLatencyPath, &file_contents)) { + ALOGD("Unable to read PCM Latency path %s", kPcmLatencyPath); + } else { + std::stringstream file_content_stream(file_contents); + int duration; + while (file_content_stream.good() && file_content_stream >> duration) { + latency_per_type.push_back(duration); + } + } + + if (latency_per_type.size() != num_type) { + ALOGD("Audio PCM Latency path doesn't match the number of features. %zu / %d", + latency_per_type.size(), num_type); + return; + } + + for (int index = 0; index < num_type; index++) { + std::vector<VendorAtomValue> values(3); + VendorAtomValue tmp; + + if (latency_per_type[index] == 0 && count_per_type[index] == 0) { + continue; + } + + tmp.set<VendorAtomValue::intValue>(index); + values[VendorAudioPcmStatsReported::kTypeFieldNumber - kVendorAtomOffset] = tmp; + + tmp.set<VendorAtomValue::intValue>(latency_per_type[index]); + values[VendorAudioPcmStatsReported::kPcmOpenLatencyAvgMsPerDayFieldNumber - + kVendorAtomOffset] = tmp; + + tmp.set<VendorAtomValue::intValue>(count_per_type[index]); + values[VendorAudioPcmStatsReported::kPcmActiveCountsPerDayFieldNumber - kVendorAtomOffset] = + tmp; + + // Send vendor atom to IStats HAL + VendorAtom event = {.reverseDomainName = "", + .atomId = PixelAtoms::Atom::kVendorAudioPcmStatsReported, + .values = std::move(values)}; + + const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event); + if (!ret.isOk()) + ALOGE("Unable to report VendorAudioPcmStatsReported at index %d", index); + } } /** @@ -1233,18 +1623,24 @@ void SysfsCollector::logVendorResumeLatencyStats(const std::shared_ptr<IStats> & ALOGE("Unable to report VendorResumeLatencyStats to Stats service"); } -bool cmp(const std::pair<int, int64_t> &a, const std::pair<int, int64_t> &b) { - return a.second > b.second; -} - /** - * Sort irq stats by irq latency, and load top 5 irq stats. + * Read and store top 5 irq stats. */ -void process_irqatom_values(std::vector<std::pair<int, int64_t>> sorted_pair, +void process_irqatom_values(std::string file_contents, int *offset, std::vector<VendorAtomValue> *values) { + const char *data = file_contents.c_str(); + int bytes_read; + int64_t irq_data; + int irq_num; + + std::vector<std::pair<int, int64_t>> irq_pair; + + while (sscanf(data + *offset, "%d %" PRId64 "\n%n", &irq_num, &irq_data, &bytes_read) == 2) { + irq_pair.push_back(std::make_pair(irq_num, irq_data)); + *offset += bytes_read; + } VendorAtomValue tmp; - sort(sorted_pair.begin(), sorted_pair.end(), cmp); - int irq_stats_size = sorted_pair.size(); + int irq_stats_size = irq_pair.size(); for (int i = 0; i < 5; i++) { if (irq_stats_size < 5 && i >= irq_stats_size) { tmp.set<VendorAtomValue::longValue>(-1); @@ -1252,9 +1648,9 @@ void process_irqatom_values(std::vector<std::pair<int, int64_t>> sorted_pair, tmp.set<VendorAtomValue::longValue>(0); values->push_back(tmp); } else { - tmp.set<VendorAtomValue::longValue>(sorted_pair[i].first); + tmp.set<VendorAtomValue::longValue>(irq_pair[i].first); values->push_back(tmp); - tmp.set<VendorAtomValue::longValue>(sorted_pair[i].second); + tmp.set<VendorAtomValue::longValue>(irq_pair[i].second); values->push_back(tmp); } } @@ -1268,93 +1664,66 @@ void SysfsCollector::logVendorLongIRQStatsReported(const std::shared_ptr<IStats> if (uart_enabled == "running") { return; } - std::string file_contents; - if (!kLongIRQMetricsPath) { + std::string irq_file_contents, storm_file_contents; + if (kLongIRQMetricsPath == nullptr || strlen(kLongIRQMetricsPath) == 0) { ALOGV("LongIRQ path not specified"); return; } - if (!ReadFileToString(kLongIRQMetricsPath, &file_contents)) { - ALOGE("Unable to LongIRQ %s - %s", kLongIRQMetricsPath, strerror(errno)); + if (!ReadFileToString(kLongIRQMetricsPath, &irq_file_contents)) { + ALOGE("Unable to read LongIRQ %s - %s", kLongIRQMetricsPath, strerror(errno)); + return; + } + if (kStormIRQMetricsPath == nullptr || strlen(kStormIRQMetricsPath) == 0) { + ALOGV("StormIRQ path not specified"); + return; + } + if (!ReadFileToString(kStormIRQMetricsPath, &storm_file_contents)) { + ALOGE("Unable to read StormIRQ %s - %s", kStormIRQMetricsPath, strerror(errno)); + return; + } + if (kIRQStatsResetPath == nullptr || strlen(kIRQStatsResetPath) == 0) { + ALOGV("IRQStatsReset path not specified"); return; } int offset = 0; int bytes_read; - const char *data = file_contents.c_str(); - int data_len = file_contents.length(); - // Get, process, store softirq stats - std::vector<std::pair<int, int64_t>> sorted_softirq_pair; - int64_t softirq_count; - if (sscanf(data + offset, "long SOFTIRQ count: %" PRId64 "\n%n", &softirq_count, &bytes_read) != - 1) + const char *data = irq_file_contents.c_str(); + + // Get, process softirq stats + int64_t irq_count; + if (sscanf(data + offset, "long SOFTIRQ count: %" PRId64 "\n%n", &irq_count, &bytes_read) != 1) return; offset += bytes_read; - if (offset >= data_len) - return; std::vector<VendorAtomValue> values; VendorAtomValue tmp; - if (softirq_count - prev_data.softirq_count < 0) { - tmp.set<VendorAtomValue::intValue>(-1); - ALOGI("long softirq count get overflow"); - } else { - tmp.set<VendorAtomValue::longValue>(softirq_count - prev_data.softirq_count); - } + tmp.set<VendorAtomValue::longValue>(irq_count); values.push_back(tmp); if (sscanf(data + offset, "long SOFTIRQ detail (num, latency):\n%n", &bytes_read) != 0) return; offset += bytes_read; - if (offset >= data_len) - return; - - // Iterate over softirq stats and record top 5 long softirq - int64_t softirq_latency; - int softirq_num; - while (sscanf(data + offset, "%d %" PRId64 "\n%n", &softirq_num, &softirq_latency, - &bytes_read) == 2) { - sorted_softirq_pair.push_back(std::make_pair(softirq_num, softirq_latency)); - offset += bytes_read; - if (offset >= data_len) - return; - } - process_irqatom_values(sorted_softirq_pair, &values); + process_irqatom_values(data, &offset, &values); - // Get, process, store irq stats - std::vector<std::pair<int, int64_t>> sorted_irq_pair; - int64_t irq_count; + // Get, process irq stats if (sscanf(data + offset, "long IRQ count: %" PRId64 "\n%n", &irq_count, &bytes_read) != 1) return; offset += bytes_read; - if (offset >= data_len) - return; - if (irq_count - prev_data.irq_count < 0) { - tmp.set<VendorAtomValue::intValue>(-1); - ALOGI("long irq count get overflow"); - } else { - tmp.set<VendorAtomValue::longValue>(irq_count - prev_data.irq_count); - } + tmp.set<VendorAtomValue::longValue>(irq_count); values.push_back(tmp); if (sscanf(data + offset, "long IRQ detail (num, latency):\n%n", &bytes_read) != 0) return; offset += bytes_read; - if (offset >= data_len) - return; + process_irqatom_values(data, &offset, &values); - int64_t irq_latency; - int irq_num; - int index = 0; - // Iterate over softirq stats and record top 5 long irq - while (sscanf(data + offset, "%d %" PRId64 "\n%n", &irq_num, &irq_latency, &bytes_read) == 2) { - sorted_irq_pair.push_back(std::make_pair(irq_num, irq_latency)); - offset += bytes_read; - if (offset >= data_len && index < 5) - return; - index += 1; - } - process_irqatom_values(sorted_irq_pair, &values); + // Get, process storm irq stats + offset = 0; + data = storm_file_contents.c_str(); + if (sscanf(data + offset, "storm IRQ detail (num, storm_count):\n%n", &bytes_read) != 0) + return; + offset += bytes_read; + process_irqatom_values(data, &offset, &values); - prev_data.softirq_count = softirq_count; - prev_data.irq_count = irq_count; // Send vendor atom to IStats HAL VendorAtom event = {.reverseDomainName = "", .atomId = PixelAtoms::Atom::kVendorLongIrqStatsReported, @@ -1362,6 +1731,12 @@ void SysfsCollector::logVendorLongIRQStatsReported(const std::shared_ptr<IStats> const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event); if (!ret.isOk()) ALOGE("Unable to report kVendorLongIRQStatsReported to Stats service"); + + // Reset irq stats + if (!WriteStringToFile(std::to_string(1), kIRQStatsResetPath)) { + ALOGE("Failed to write to stats_reset"); + return; + } } void SysfsCollector::logPartitionUsedSpace(const std::shared_ptr<IStats> &stats_client) { @@ -1510,6 +1885,17 @@ void SysfsCollector::logPcieLinkStats(const std::shared_ptr<IStats> &stats_clien } } +/** + * Read the contents of kPowerMitigationDurationPath and report them. + */ +void SysfsCollector::logMitigationDurationCounts(const std::shared_ptr<IStats> &stats_client) { + if (kPowerMitigationDurationPath == nullptr || strlen(kPowerMitigationDurationPath) == 0) { + ALOGE("Mitigation Duration path is invalid!"); + return; + } + mitigation_duration_reporter_.logMitigationDuration(stats_client, kPowerMitigationDurationPath); +} + void SysfsCollector::logPerDay() { const std::shared_ptr<IStats> stats_client = getStatsService(); if (!stats_client) { @@ -1527,6 +1913,7 @@ void SysfsCollector::logPerDay() { logBlockStatsReported(stats_client); logCodec1Failed(stats_client); logCodecFailed(stats_client); + logDisplayStats(stats_client); logF2fsStats(stats_client); logF2fsAtomicWriteInfo(stats_client); logF2fsCompressionInfo(stats_client); @@ -1547,6 +1934,11 @@ void SysfsCollector::logPerDay() { logVendorResumeLatencyStats(stats_client); logPartitionUsedSpace(stats_client); logPcieLinkStats(stats_client); + logMitigationDurationCounts(stats_client); + logVendorAudioPdmStatsReported(stats_client); + logWavesStats(stats_client); + logAdaptedInfoStats(stats_client); + logPcmUsageStats(stats_client); } void SysfsCollector::aggregatePer5Min() { diff --git a/pixelstats/UeventListener.cpp b/pixelstats/UeventListener.cpp index 07c8c954..8af43a01 100644 --- a/pixelstats/UeventListener.cpp +++ b/pixelstats/UeventListener.cpp @@ -66,6 +66,7 @@ using aidl::android::frameworks::stats::VendorAtomValue; using android::sp; using android::base::ReadFileToString; using android::base::WriteStringToFile; +using android::hardware::google::pixel::PixelAtoms::GpuEvent; using android::hardware::google::pixel::PixelAtoms::PdVidPid; using android::hardware::google::pixel::PixelAtoms::VendorHardwareFailed; using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat; @@ -271,6 +272,34 @@ void UeventListener::ReportTypeCPartnerId(const std::shared_ptr<IStats> &stats_c } } +void UeventListener::ReportGpuEvent(const std::shared_ptr<IStats> &stats_client, const char *driver, + const char *gpu_event_type, const char *gpu_event_info) { + if (!stats_client || !driver || strncmp(driver, "DRIVER=mali", strlen("DRIVER=mali")) || + !gpu_event_type || !gpu_event_info) + return; + + std::vector<std::string> type = android::base::Split(gpu_event_type, "="); + std::vector<std::string> info = android::base::Split(gpu_event_info, "="); + + if (type.size() != 2 || info.size() != 2) + return; + + if (type[0] != "GPU_UEVENT_TYPE" || info[0] != "GPU_UEVENT_INFO") + return; + + auto event_type = kGpuEventTypeStrToEnum.find(type[1]); + auto event_info = kGpuEventInfoStrToEnum.find(info[1]); + if (event_type == kGpuEventTypeStrToEnum.end() || event_info == kGpuEventInfoStrToEnum.end()) + return; + + VendorAtom event = {.reverseDomainName = "", + .atomId = PixelAtoms::Atom::kGpuEvent, + .values = {event_type->second, event_info->second}}; + const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event); + if (!ret.isOk()) + ALOGE("Unable to report GPU event."); +} + bool UeventListener::ProcessUevent() { char msg[UEVENT_MSG_LEN + 2]; char *cp; @@ -278,6 +307,7 @@ bool UeventListener::ProcessUevent() { const char *mic_break_status, *mic_degrade_status; const char *devpath; bool collect_partner_id = false; + const char *gpu_event_type = nullptr, *gpu_event_info = nullptr; int n; if (uevent_fd_ < 0) { @@ -333,6 +363,10 @@ bool UeventListener::ProcessUevent() { subsystem = cp; } else if (!strncmp(cp, kTypeCPartnerUevent.c_str(), kTypeCPartnerUevent.size())) { collect_partner_id = true; + } else if (!strncmp(cp, "GPU_UEVENT_TYPE=", strlen("GPU_UEVENT_TYPE="))) { + gpu_event_type = cp; + } else if (!strncmp(cp, "GPU_UEVENT_INFO=", strlen("GPU_UEVENT_INFO="))) { + gpu_event_info = cp; } /* advance to after the next \0 */ while (*cp++) { @@ -352,6 +386,7 @@ bool UeventListener::ProcessUevent() { if (collect_partner_id) { ReportTypeCPartnerId(stats_client); } + ReportGpuEvent(stats_client, driver, gpu_event_type, gpu_event_info); } if (log_fd_ > 0) { diff --git a/pixelstats/include/pixelstats/DisplayStatsReporter.h b/pixelstats/include/pixelstats/DisplayStatsReporter.h new file mode 100644 index 00000000..35435583 --- /dev/null +++ b/pixelstats/include/pixelstats/DisplayStatsReporter.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2023 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. + */ + +#ifndef HARDWARE_GOOGLE_PIXEL_PIXELSTATS_DISPLAYSTATSREPORTER_H +#define HARDWARE_GOOGLE_PIXEL_PIXELSTATS_DISPLAYSTATSREPORTER_H + +#include <aidl/android/frameworks/stats/IStats.h> +#include <hardware/google/pixel/pixelstats/pixelatoms.pb.h> + +#include <string> + +namespace android { +namespace hardware { +namespace google { +namespace pixel { + +using aidl::android::frameworks::stats::IStats; +using aidl::android::frameworks::stats::VendorAtomValue; + +/** + * A class to upload Pixel Display Stats metrics + */ +class DisplayStatsReporter { + public: + DisplayStatsReporter(); + void logDisplayStats(const std::shared_ptr<IStats> &stats_client, + const std::vector<std::string> &display_stats_paths); + + private: + struct DisplayPanelErrorStats { + int64_t primary_error_count_te; + int64_t primary_error_count_unknown; + int64_t secondary_error_count_te; + int64_t secondary_error_count_unknown; + }; + + // Proto messages are 1-indexed and VendorAtom field numbers start at 2, so + // store everything in the values array at the index of the field number + // -2. + const int kVendorAtomOffset = 2; + const int kNumOfDisplayPanelErrorStats = 4; + struct DisplayPanelErrorStats prev_data_; + + void logDisplayPanelErrorStats(const std::shared_ptr<IStats> &stats_client, + const std::vector<std::string> &display_stats_paths); + bool captureDisplayPanelErrorStats(const std::vector<std::string> &display_stats_paths, + struct DisplayPanelErrorStats *cur_data); + bool readDisplayPanelErrorCount(const std::string &path, int64_t *val); +}; + +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android + +#endif // HARDWARE_GOOGLE_PIXEL_PIXELSTATS_DISPLAYSTATSREPORTER_H diff --git a/pixelstats/include/pixelstats/MitigationDurationReporter.h b/pixelstats/include/pixelstats/MitigationDurationReporter.h new file mode 100644 index 00000000..44a6bc0e --- /dev/null +++ b/pixelstats/include/pixelstats/MitigationDurationReporter.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2023 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. + */ + +#ifndef HARDWARE_GOOGLE_PIXEL_PIXELSTATS_MITIGATIONDURATIONREPORTER_H +#define HARDWARE_GOOGLE_PIXEL_PIXELSTATS_MITIGATIONDURATIONREPORTER_H + +#include <aidl/android/frameworks/stats/IStats.h> +#include <hardware/google/pixel/pixelstats/pixelatoms.pb.h> + +#include <map> +#include <string> + +namespace android { +namespace hardware { +namespace google { +namespace pixel { + +using aidl::android::frameworks::stats::IStats; +using aidl::android::frameworks::stats::VendorAtomValue; + +#define MITIGATION_DURATION_MAIN_COUNT 12 +#define MITIGATION_DURATION_SUB_COUNT 12 + +/** + * A class to upload Pixel Mitigation Duration metrics + */ +class MitigationDurationReporter { + public: + MitigationDurationReporter(); + void logMitigationDuration(const std::shared_ptr<IStats> &stats_client, + const std::string &path); + + private: + struct IrqDurationCounts { + int uvlo1_none; + int uvlo1_mmwave; + int uvlo1_rffe; + int uvlo2_none; + int uvlo2_mmwave; + int uvlo2_rffe; + int batoilo_none; + int batoilo_mmwave; + int batoilo_rffe; + int main[MITIGATION_DURATION_MAIN_COUNT]; + int sub[MITIGATION_DURATION_SUB_COUNT]; + }; + + // Proto messages are 1-indexed and VendorAtom field numbers start at 2, so + // store everything in the values array at the index of the field number + // -2. + const int kVendorAtomOffset = 2; + const int kExpectedNumberOfLines = 33; + const std::string kGreaterThanTenMsSysfsNode = "/greater_than_10ms_count"; + + void valueAssignmentHelper(std::vector<VendorAtomValue> *values, int *val, int fieldNumber); + + int updateStat(const std::string *line, int *val); + + bool getIrqDurationCountHelper(const std::string kMitigationDurationFile, + struct IrqDurationCounts *counts); + bool getStatFromLine(const std::string *line, int *val); +}; + +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android + +#endif // HARDWARE_GOOGLE_PIXEL_PIXELSTATS_MITIGATIONDURATIONREPORTER_H diff --git a/pixelstats/include/pixelstats/SysfsCollector.h b/pixelstats/include/pixelstats/SysfsCollector.h index 1054cc54..494acd71 100644 --- a/pixelstats/include/pixelstats/SysfsCollector.h +++ b/pixelstats/include/pixelstats/SysfsCollector.h @@ -23,6 +23,8 @@ #include "BatteryEEPROMReporter.h" #include "BatteryHealthReporter.h" #include "BrownoutDetectedReporter.h" +#include "DisplayStatsReporter.h" +#include "MitigationDurationReporter.h" #include "MitigationStatsReporter.h" #include "MmMetricsReporter.h" #include "TempResidencyReporter.h" @@ -59,6 +61,7 @@ class SysfsCollector { const char *const ZramBdStatPath; const char *const EEPROMPath; const char *const MitigationPath; + const char *const MitigationDurationPath; const char *const BrownoutLogPath; const char *const BrownoutReasonProp; const char *const SpeakerTemperaturePath; @@ -68,12 +71,22 @@ class SysfsCollector { const int BlockStatsLength; const char *const AmsRatePath; const std::vector<std::string> ThermalStatsPaths; + const std::vector<std::string> DisplayStatsPaths; const char *const CCARatePath; const std::vector<std::pair<std::string, std::string>> TempResidencyAndResetPaths; const char *const LongIRQMetricsPath; + const char *const StormIRQMetricsPath; + const char *const IRQStatsResetPath; const char *const ResumeLatencyMetricsPath; const char *const ModemPcieLinkStatsPath; const char *const WifiPcieLinkStatsPath; + const char *const PDMStatePath; + const char *const WavesPath; + const char *const AdaptedInfoCountPath; + const char *const AdaptedInfoDurationPath; + const char *const PcmLatencyPath; + const char *const PcmCountPath; + const char *const TotalCallCountPath; }; SysfsCollector(const struct SysfsPaths &paths); @@ -109,6 +122,9 @@ class SysfsCollector { void logSpeakerHealthStats(const std::shared_ptr<IStats> &stats_client); void logF2fsSmartIdleMaintEnabled(const std::shared_ptr<IStats> &stats_client); void logThermalStats(const std::shared_ptr<IStats> &stats_client); + void logMitigationDurationCounts(const std::shared_ptr<IStats> &stats_client); + void logDisplayStats(const std::shared_ptr<IStats> &stats_client); + void logVendorAudioPdmStatsReported(const std::shared_ptr<IStats> &stats_client); void reportSlowIoFromFile(const std::shared_ptr<IStats> &stats_client, const char *path, const VendorSlowIo::IoOperation &operation_s); @@ -121,6 +137,9 @@ class SysfsCollector { void logVendorResumeLatencyStats(const std::shared_ptr<IStats> &stats_client); void logPartitionUsedSpace(const std::shared_ptr<IStats> &stats_client); void logPcieLinkStats(const std::shared_ptr<IStats> &stats_client); + void logWavesStats(const std::shared_ptr<IStats> &stats_client); + void logAdaptedInfoStats(const std::shared_ptr<IStats> &stats_client); + void logPcmUsageStats(const std::shared_ptr<IStats> &stats_client); const char *const kSlowioReadCntPath; const char *const kSlowioWriteCntPath; @@ -143,6 +162,7 @@ class SysfsCollector { const char *const kBrownoutLogPath; const char *const kBrownoutReasonProp; const char *const kPowerMitigationStatsPath; + const char *const kPowerMitigationDurationPath; const char *const kSpeakerTemperaturePath; const char *const kSpeakerExcursionPath; const char *const kSpeakerHeartbeatPath; @@ -153,15 +173,27 @@ class SysfsCollector { const char *const kCCARatePath; const std::vector<std::pair<std::string, std::string>> kTempResidencyAndResetPaths; const char *const kLongIRQMetricsPath; + const char *const kStormIRQMetricsPath; + const char *const kIRQStatsResetPath; const char *const kResumeLatencyMetricsPath; const char *const kModemPcieLinkStatsPath; const char *const kWifiPcieLinkStatsPath; + const std::vector<std::string> kDisplayStatsPaths; + const char *const kPDMStatePath; + const char *const kWavesPath; + const char *const kAdaptedInfoCountPath; + const char *const kAdaptedInfoDurationPath; + const char *const kPcmLatencyPath; + const char *const kPcmCountPath; + const char *const kTotalCallCountPath; BatteryEEPROMReporter battery_EEPROM_reporter_; MmMetricsReporter mm_metrics_reporter_; MitigationStatsReporter mitigation_stats_reporter_; + MitigationDurationReporter mitigation_duration_reporter_; BrownoutDetectedReporter brownout_detected_reporter_; ThermalStatsReporter thermal_stats_reporter_; + DisplayStatsReporter display_stats_reporter_; BatteryHealthReporter battery_health_reporter_; TempResidencyReporter temp_residency_reporter_; // Proto messages are 1-indexed and VendorAtom field numbers start at 2, so @@ -173,8 +205,6 @@ class SysfsCollector { int64_t prev_huge_pages_since_boot_ = -1; struct perf_metrics_data { - int64_t softirq_count; - int64_t irq_count; uint64_t resume_latency_sum_ms; int64_t resume_count; std::vector<int64_t> resume_latency_buckets; diff --git a/pixelstats/include/pixelstats/UeventListener.h b/pixelstats/include/pixelstats/UeventListener.h index 5316afaa..352beb88 100644 --- a/pixelstats/include/pixelstats/UeventListener.h +++ b/pixelstats/include/pixelstats/UeventListener.h @@ -88,6 +88,8 @@ class UeventListener { void ReportBatteryCapacityFGEvent(const std::shared_ptr<IStats> &stats_client, const char *subsystem); void ReportTypeCPartnerId(const std::shared_ptr<IStats> &stats_client); + void ReportGpuEvent(const std::shared_ptr<IStats> &stats_client, const char *driver, + const char *gpu_event_type, const char *gpu_event_info); const std::string kAudioUevent; const std::string kBatterySSOCPath; @@ -97,6 +99,47 @@ class UeventListener { const std::string kTypeCPartnerVidPath; const std::string kTypeCPartnerPidPath; + const std::unordered_map<std::string, PixelAtoms::GpuEvent::GpuEventType> + kGpuEventTypeStrToEnum{ + {"KMD_ERROR", + PixelAtoms::GpuEvent::GpuEventType::GpuEvent_GpuEventType_MALI_KMD_ERROR}, + {"GPU_RESET", + PixelAtoms::GpuEvent::GpuEventType::GpuEvent_GpuEventType_MALI_GPU_RESET}}; + + const std::unordered_map<std::string, PixelAtoms::GpuEvent::GpuEventInfo> + kGpuEventInfoStrToEnum{ + {"CSG_REQ_STATUS_UPDATE", + PixelAtoms::GpuEvent::GpuEventInfo:: + GpuEvent_GpuEventInfo_MALI_CSG_REQ_STATUS_UPDATE}, + {"CSG_SUSPEND", + PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_CSG_SUSPEND}, + {"CSG_SLOTS_SUSPEND", PixelAtoms::GpuEvent::GpuEventInfo:: + GpuEvent_GpuEventInfo_MALI_CSG_SLOTS_SUSPEND}, + {"CSG_GROUP_SUSPEND", PixelAtoms::GpuEvent::GpuEventInfo:: + GpuEvent_GpuEventInfo_MALI_CSG_GROUP_SUSPEND}, + {"CSG_EP_CFG", + PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_CSG_EP_CFG}, + {"CSG_SLOTS_START", PixelAtoms::GpuEvent::GpuEventInfo:: + GpuEvent_GpuEventInfo_MALI_CSG_SLOTS_START}, + {"GROUP_TERM", + PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_GROUP_TERM}, + {"QUEUE_START", + PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_QUEUE_START}, + {"QUEUE_STOP", + PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_QUEUE_STOP}, + {"QUEUE_STOP_ACK", + PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_QUEUE_STOP_ACK}, + {"CSG_SLOT_READY", + PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_CSG_SLOT_READY}, + {"L2_PM_TIMEOUT", + PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_L2_PM_TIMEOUT}, + {"PM_TIMEOUT", + PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_PM_TIMEOUT}, + {"CSF_RESET_OK", + PixelAtoms::GpuEvent::GpuEventInfo::GpuEvent_GpuEventInfo_MALI_CSF_RESET_OK}, + {"CSF_RESET_FAILED", PixelAtoms::GpuEvent::GpuEventInfo:: + GpuEvent_GpuEventInfo_MALI_CSF_RESET_FAILED}}; + BatteryCapacityReporter battery_capacity_reporter_; ChargeStatsReporter charge_stats_reporter_; diff --git a/pixelstats/pixelatoms.proto b/pixelstats/pixelatoms.proto index 05421fc5..3f5e76f4 100644 --- a/pixelstats/pixelatoms.proto +++ b/pixelstats/pixelatoms.proto @@ -103,9 +103,15 @@ message Atom { VibratorPlaycountReported vibrator_playcount_reported = 105049; VibratorLatencyReported vibrator_latency_reported = 105050; VibratorErrorsReported vibrator_errors_reported = 105051; - F2fsAtomicWriteInfo f2fs_atomic_write_info = 105052; PartitionsUsedSpaceReported partition_used_space_reported = 105053; + PowerMitigationDurationCounts mitigation_duration = 105054; // moved from atoms.proto + DisplayPanelErrorStats display_panel_error_stats = 105055; + VendorAudioPdmStatsReported vendor_audio_pdm_stats_reported = 105056; + VendorAudioThirdPartyEffectStatsReported vendor_audio_third_party_effect_stats_reported = 105057; + VendorAudioAdaptedInfoStatsReported vendor_audio_adapted_info_stats_reported = 105058; + GpuEvent gpu_event = 105059; + VendorAudioPcmStatsReported vendor_audio_pcm_stats_reported = 105060; } // AOSP atom ID range ends at 109999 reserved 109997; // reserved for VtsVendorAtomJavaTest test atom @@ -152,6 +158,8 @@ message ChargeStats { ADAPTER_TYPE_EXT1 = 27; ADAPTER_TYPE_EXT2 = 28; ADAPTER_TYPE_EXT_UNKNOWN = 29; + ADAPTER_TYPE_USB_UNKNOWN = 30; + ADAPTER_TYPE_WLC_UNKNOWN = 31; } optional string reverse_domain_name = 1; /* Type of charge adapter, enumerated above. */ @@ -949,6 +957,21 @@ message ThermalDfsStats { } /** + * Log Display Panel error statistics. + */ +message DisplayPanelErrorStats { + optional string reverse_domain_name = 1; + // The error count due to Tear Effect on primary display panel. + optional int32 primary_error_count_te = 2; + // The error count due to unknown reason on primary display panel. + optional int32 primary_error_count_unknown = 3; + // The error count due to Tear Effect on primary display panel. + optional int32 secondary_error_count_te = 4; + // The error count due to unknown reason on secondary display panel. + optional int32 secondary_error_count_unknown = 5; +} + +/** * Log how many segments have been reclaimed in a specific GC mode. */ message F2fsGcSegmentInfo { @@ -1290,23 +1313,51 @@ message BlockStatsReported { */ message VendorAudioHardwareStatsReported { optional string reverse_domain_name = 1; - /* The percentage of calls in a day where auto-mic-switch triggered. - * It represented as a fixed-point integer with three decimal place. - * E.g.:12.345% is repsented by 12345. + /* The number of calls in a day where CCA is active. + * CCA can only be applied under some radio bands. */ optional int32 milli_rate_of_ams_per_day = 2; - /* The percentage of calls in a day where CCA is active. - * It represented as a fixed-point and rounded integer. - * E.g.:12.345% is represented by 12. - * CCA can only be applied under some radio bands. - */ + // cca_active: obsoleted UI enable & algorithm is active (C1) + // replaced by cca_active_count_per_day + optional int32 rate_of_cca_active_per_day = 3 [deprecated = true]; + + // cca_enable: obsoleted UI enable & algorithm is inactive field (C2) + // replaced by cca_enable_count_per_day + optional int32 rate_of_cca_enable_per_day = 4 [deprecated = true]; + + enum Source { + VOIP = 0; + VOICE = 1; + } + + /* source: identify whether this atom is for voice or voip case. */ + optional Source source = 5; + + /* total_call_count_per_day: count total number of call per day. */ + optional int32 total_call_count_per_day = 6; + + /* cca_active: UI enable & algorithm is active (C1 or C3) */ + optional int32 cca_active_count_per_day = 7; + + /* cca_enable: UI enable & algorithm is inactive (C2 or C4) */ + optional int32 cca_enable_count_per_day = 8; +} + +/** + * Logs the reported vendor audio PDM stats. + * PDM stats are used to show background noise level during voice/voip calling. + * Each of the atom will show only one type of background noises. There are at most 4 types. + * Thus, this atoms will be reported at most 4 times to show all types. + */ +message VendorAudioPdmStatsReported { + optional string reverse_domain_name = 1; - /* cca_active: UI enable & algorithm is active (C1) */ - optional int32 rate_of_cca_active_per_day = 3; + /* index of the pdm to report. There are 4 pdm instances. So, the value is in the range 1-4 */ + optional int32 pdm_index = 2; - /* cca_enable: UI enable & algorithm is inactive. (C2) */ - optional int32 rate_of_cca_enable_per_day = 4; + /* State of the pdm to report. There is only two value 1 for good and 0 for bad. */ + optional int32 state = 3; } /* @@ -1346,6 +1397,17 @@ message VendorLongIRQStatsReported { optional int64 top4_irq_latency_us = 21; optional int64 top5_irq_num = 22; optional int64 top5_irq_latency_us = 23; + + optional int64 storm_irq_top1_num = 24; + optional int64 storm_irq_top1_count = 25; + optional int64 storm_irq_top2_num = 26; + optional int64 storm_irq_top2_count = 27; + optional int64 storm_irq_top3_num = 28; + optional int64 storm_irq_top3_count = 29; + optional int64 storm_irq_top4_num = 30; + optional int64 storm_irq_top4_count = 31; + optional int64 storm_irq_top5_num= 32; + optional int64 storm_irq_top5_count = 33; } /** @@ -1561,7 +1623,7 @@ message BrownoutDetected { // Triggered DVFS State: Channel 6 optional int32 dvfs_channel6 = 37; // brownout reason - optional int32 brownout_reason = 38; + optional BrownoutReason brownout_reason = 38; } /* @@ -1734,4 +1796,197 @@ message PartitionsUsedSpaceReported { optional Directory directory = 2; optional int64 free_bytes = 3; optional int64 total_bytes = 4; -}
\ No newline at end of file +} + +message GpuEvent { + enum GpuEventType { + MALI_TYPE_NONE = 0; + MALI_KMD_ERROR = 1; + MALI_GPU_RESET = 2; + } + enum GpuEventInfo { + MALI_INFO_NONE = 0; + MALI_CSG_REQ_STATUS_UPDATE = 1; + MALI_CSG_SUSPEND = 2; + MALI_CSG_SLOTS_SUSPEND = 3; + MALI_CSG_GROUP_SUSPEND = 4; + MALI_CSG_EP_CFG = 5; + MALI_CSG_SLOTS_START = 6; + MALI_GROUP_TERM = 7; + MALI_QUEUE_START = 8; + MALI_QUEUE_STOP = 9; + MALI_QUEUE_STOP_ACK = 10; + MALI_CSG_SLOT_READY = 11; + MALI_L2_PM_TIMEOUT = 12; + MALI_PM_TIMEOUT = 13; + MALI_CSF_RESET_OK = 14; + MALI_CSF_RESET_FAILED = 15; + } + + /* Vendor reverse domain name (expecting "com.google.pixel"). */ + optional string reverse_domain_name = 1; + /* + * Type of the GPU event. Possible values depend on the platform GPU. + * Eg, MALI_KMD_ERROR, MALI_GPU_RESET. + */ + optional GpuEventType gpu_event_type = 2; + /* + * Additional information about the GPU event. Possible values depend + * on the platform GPU. + * Eg, MALI_PM_TIMEOUT, MALI_CSF_RESET_OK. + */ + optional GpuEventInfo gpu_event_info = 3; +} +/** + * Log mitigation duration. + */ +message PowerMitigationDurationCounts { + optional string reverse_domain_name = 1; + // Count of UVLO1 greater than threshold without any other concurrent IRQs. + optional int32 greater_than_thresh_uvlo1_none = 2; + // Count of UVLO1 IRQ + MMWAVE IRQ with duration greater than threshold. + optional int32 greater_than_thresh_uvlo1_mmwave = 3; + // Count of UVLO1 IRQ + RFFE IRQ with duration greater than threshold. + optional int32 greater_than_thresh_uvlo1_rffe = 4; + // Count of UVLO2 greater than threshold without any other concurrent IRQs. + optional int32 greater_than_thresh_uvlo2_none = 5; + // Count of UVLO2 IRQ + MMWAVE IRQ with duration greater than threshold. + optional int32 greater_than_thresh_uvlo2_mmwave = 6; + // Count of UVLO2 IRQ + RFFE IRQ with duration greater than threshold. + optional int32 greater_than_thresh_uvlo2_rffe = 7; + // Count of BATOILO greater than threshold without any other concurrent IRQs. + optional int32 greater_than_thresh_batoilo_none = 8; + // Count of BATOILO IRQ + MMWAVE IRQ with duration greater than threshold. + optional int32 greater_than_thresh_batoilo_mmwave = 9; + // Count of BATOILO IRQ + RFFE IRQ with duration greater than threshold. + optional int32 greater_than_thresh_batoilo_rffe = 10; + + // IRQ duration of main regulator indices 0-11 greater than threshold. + optional int32 greater_than_thresh_main_0 = 11; + optional int32 greater_than_thresh_main_1 = 12; + optional int32 greater_than_thresh_main_2 = 13; + optional int32 greater_than_thresh_main_3 = 14; + optional int32 greater_than_thresh_main_4 = 15; + optional int32 greater_than_thresh_main_5 = 16; + optional int32 greater_than_thresh_main_6 = 17; + optional int32 greater_than_thresh_main_7 = 18; + optional int32 greater_than_thresh_main_8 = 19; + optional int32 greater_than_thresh_main_9 = 20; + optional int32 greater_than_thresh_main_10 = 21; + optional int32 greater_than_thresh_main_11 = 22; + + // IRQ duration of sub regulator indices 0-11 greater than threshold. + optional int32 greater_than_thresh_sub_0 = 23; + optional int32 greater_than_thresh_sub_1 = 24; + optional int32 greater_than_thresh_sub_2 = 25; + optional int32 greater_than_thresh_sub_3 = 26; + optional int32 greater_than_thresh_sub_4 = 27; + optional int32 greater_than_thresh_sub_5 = 28; + optional int32 greater_than_thresh_sub_6 = 29; + optional int32 greater_than_thresh_sub_7 = 30; + optional int32 greater_than_thresh_sub_8 = 31; + optional int32 greater_than_thresh_sub_9 = 32; + optional int32 greater_than_thresh_sub_10 = 33; + optional int32 greater_than_thresh_sub_11 = 34; +} + +/* + * Logs the third party audio effects stats. + * Third party audio effects stats includes duration in milliseconds for each + * instance of the effects (speaker, USB, etc.). + */ +message VendorAudioThirdPartyEffectStatsReported { + /* Vendor reverse domain name (expecting "com.google.pixel"). */ + optional string reverse_domain_name = 1; + + enum InstanceId { + OTHER = 0; + SPEAKER = 1; + USB = 2; + BT_A2DP = 3; + BT_LE = 4; + } + /* Instance of the effect. */ + optional InstanceId instance = 2; + /* Active duration in milliseconds per day for volume range 0. */ + optional int32 volume_range_0_active_ms_per_day = 3; + /* Active duration in milliseconds per day for volume range 1. */ + optional int32 volume_range_1_active_ms_per_day = 4; + /* Active duration in milliseconds per day for volume range 2. */ + optional int32 volume_range_2_active_ms_per_day = 5; + /* Active duration in milliseconds per day for volume range 3. */ + optional int32 volume_range_3_active_ms_per_day = 6; + /* Active duration in milliseconds per day for volume range 4. */ + optional int32 volume_range_4_active_ms_per_day = 7; + /* Active duration in milliseconds per day for volume range 5. */ + optional int32 volume_range_5_active_ms_per_day = 8; + /* Active duration in milliseconds per day for volume range 6. */ + optional int32 volume_range_6_active_ms_per_day = 9; + /* Active duration in milliseconds per day for volume range 7. */ + optional int32 volume_range_7_active_ms_per_day = 10; + /* Active duration in milliseconds per day for volume range 8. */ + optional int32 volume_range_8_active_ms_per_day = 11; + /* Active duration in milliseconds per day for volume range 9. */ + optional int32 volume_range_9_active_ms_per_day = 12; +} + +/* + * Logs the Audio Adapted information stats. + * Two stats are recorded, count and duration (in ms) per features. + */ +message VendorAudioAdaptedInfoStatsReported { + /* Vendor reverse domain name */ + optional string reverse_domain_name = 1; + + enum AdaptedInfoFeature { + UNKNOWN = 0; + BATTERY_ADAPTED_AUDIO_CONTROL = 1; + MEDIA_PLAYBACK_THERMAL_THROTTLE = 2; + TELEPHONY_THERMAL_THROTTLE = 3; + ACOUSTIC_SHOCK = 4; + SPATIAL_AUDIO = 5; + }; + /* Feature to record the stats */ + optional AdaptedInfoFeature feature_id = 2; + /* Number of time the feature is active */ + optional int32 active_counts_per_day = 3; + /* Duration the feature is active in milliseconds */ + optional int32 active_duration_ms_per_day = 4; +} + +/* + * Logs the audio PCM usage stats. + * PCM usage includes average latency and total active count per day. + */ +message VendorAudioPcmStatsReported { + /* Vendor reverse domain name */ + optional string reverse_domain_name = 1; + + enum HalPcmType { + UNKNOWN = 0; + DEEPBUFFER = 1; + LOWLATENCY = 2; + MMAP_PLAY = 3; + RAW_PLAY = 4; + IMMERSIVE = 5; + HAPTIC = 6; + COMPRESS = 7; + MMAP_REC = 8; + RAW_REC = 9; + AUDIO_REC = 10; + HIFI_RX = 11; + HIFI_TX = 12; + IMMUTABLE_RX = 13; + CUSTOM_PCM_1 = 14; + CUSTOM_PCM_2 = 15; + CUSTOM_PCM_3 = 16; + CUSTOM_PCM_4 = 17; + CUSTOM_PCM_5 = 18; + }; + /* Type of PCM */ + optional HalPcmType type = 2; + /* Average latency in millisecond of the pcm type per day. */ + optional int32 pcm_open_latency_avg_ms_per_day = 3; + /* Total active count of the pcm type per day. */ + optional int32 pcm_active_counts_per_day = 4; +} diff --git a/power-libperfmgr/aidl/PowerSessionManager.cpp b/power-libperfmgr/aidl/PowerSessionManager.cpp index e66ff5f3..2d2aad25 100644 --- a/power-libperfmgr/aidl/PowerSessionManager.cpp +++ b/power-libperfmgr/aidl/PowerSessionManager.cpp @@ -72,7 +72,11 @@ static void set_uclamp_min(int tid, int min) { int ret = sched_setattr(tid, &attr, 0); if (ret) { - ALOGW("sched_setattr failed for thread %d, err=%d", tid, errno); + if (errno == ESRCH) { + ALOGV("sched_setattr failed for thread %d, err=%d", tid, errno); + } else { + ALOGW("sched_setattr failed for thread %d, err=%d", tid, errno); + } } } } // namespace diff --git a/power-libperfmgr/libperfmgr/FileNode.cc b/power-libperfmgr/libperfmgr/FileNode.cc index 88417848..05f0746d 100644 --- a/power-libperfmgr/libperfmgr/FileNode.cc +++ b/power-libperfmgr/libperfmgr/FileNode.cc @@ -31,11 +31,12 @@ namespace android { namespace perfmgr { FileNode::FileNode(std::string name, std::string node_path, std::vector<RequestGroup> req_sorted, - std::size_t default_val_index, bool reset_on_init, bool truncate, bool hold_fd) + std::size_t default_val_index, bool reset_on_init, bool truncate, bool hold_fd, bool write_only) : Node(std::move(name), std::move(node_path), std::move(req_sorted), default_val_index, reset_on_init), hold_fd_(hold_fd), truncate_(truncate), + write_only_(write_only), warn_timeout_(android::base::GetBoolProperty("ro.debuggable", false) ? 5ms : 50ms) {} std::chrono::milliseconds FileNode::Update(bool log_error) { @@ -110,7 +111,7 @@ bool FileNode::GetTruncate() const { void FileNode::DumpToFd(int fd) const { std::string node_value; - if (!android::base::ReadFileToString(node_path_, &node_value)) { + if (!write_only_ && !android::base::ReadFileToString(node_path_, &node_value)) { LOG(ERROR) << "Failed to read node path: " << node_path_; } node_value = android::base::Trim(node_value); diff --git a/power-libperfmgr/libperfmgr/HintManager.cc b/power-libperfmgr/libperfmgr/HintManager.cc index 8c84c685..dd313ef5 100644 --- a/power-libperfmgr/libperfmgr/HintManager.cc +++ b/power-libperfmgr/libperfmgr/HintManager.cc @@ -495,9 +495,19 @@ std::vector<std::unique_ptr<Node>> HintManager::ParseNodes( LOG(VERBOSE) << "Node[" << i << "]'s HoldFd: " << std::boolalpha << hold_fd << std::noboolalpha; + bool write_only = false; + if (nodes[i]["WriteOnly"].empty() || !nodes[i]["WriteOnly"].isBool()) { + LOG(INFO) << "Failed to read Node[" << i + << "]'s WriteOnly, set to 'false'"; + } else { + write_only = nodes[i]["WriteOnly"].asBool(); + } + LOG(VERBOSE) << "Node[" << i << "]'s WriteOnly: " << std::boolalpha + << write_only << std::noboolalpha; + nodes_parsed.emplace_back(std::make_unique<FileNode>( name, path, values_parsed, static_cast<std::size_t>(default_index), reset, - truncate, hold_fd)); + truncate, hold_fd, write_only)); } else { nodes_parsed.emplace_back(std::make_unique<PropertyNode>( name, path, values_parsed, diff --git a/power-libperfmgr/libperfmgr/include/perfmgr/FileNode.h b/power-libperfmgr/libperfmgr/include/perfmgr/FileNode.h index 5e97d276..bb8a2a79 100644 --- a/power-libperfmgr/libperfmgr/include/perfmgr/FileNode.h +++ b/power-libperfmgr/libperfmgr/include/perfmgr/FileNode.h @@ -33,7 +33,7 @@ class FileNode : public Node { public: FileNode(std::string name, std::string node_path, std::vector<RequestGroup> req_sorted, std::size_t default_val_index, bool reset_on_init, bool truncate, - bool hold_fd = false); + bool hold_fd = false, bool write_only = false); std::chrono::milliseconds Update(bool log_error) override; @@ -48,6 +48,8 @@ class FileNode : public Node { const bool hold_fd_; const bool truncate_; + // node will be read in DumpToFd + const bool write_only_; const std::chrono::milliseconds warn_timeout_; android::base::unique_fd fd_; }; diff --git a/power-libperfmgr/libperfmgr/tests/RequestGroupTest.cc b/power-libperfmgr/libperfmgr/tests/RequestGroupTest.cc index 8021a7e8..c23c8211 100644 --- a/power-libperfmgr/libperfmgr/tests/RequestGroupTest.cc +++ b/power-libperfmgr/libperfmgr/tests/RequestGroupTest.cc @@ -63,7 +63,7 @@ TEST(RequestGroupTest, AddRequestNoExpireTest) { ReqTime::max() - std::chrono::steady_clock::now()); EXPECT_NEAR(expect.count(), expire_time.count(), kTIMING_TOLERANCE_MS); // expire time is greater than 1 year - EXPECT_LE(365 * 24 * 60 * 60 * 1000, expire_time.count()); + EXPECT_LE(365ll * 24 * 60 * 60 * 1000, expire_time.count()); EXPECT_EQ(true, active); } diff --git a/thermal/Android.bp b/thermal/Android.bp index 86f6cb69..61403b31 100644 --- a/thermal/Android.bp +++ b/thermal/Android.bp @@ -3,80 +3,119 @@ package { } cc_binary { - name: "android.hardware.thermal-service.pixel", - srcs: [ - "service.cpp", - "Thermal.cpp", - "thermal-helper.cpp", - "utils/thermal_throttling.cpp", - "utils/thermal_info.cpp", - "utils/thermal_files.cpp", - "utils/power_files.cpp", - "utils/powerhal_helper.cpp", - "utils/thermal_stats_helper.cpp", - "utils/thermal_watcher.cpp", - ], - vendor: true, - relative_install_path: "hw", - vintf_fragments: [ - "android.hardware.thermal-service.pixel.xml" - ], - init_rc: [ - "android.hardware.thermal-service.pixel.rc", - ], - shared_libs: [ - "libbase", - "libcutils", - "libjsoncpp", - "libutils", - "libnl", - "libbinder_ndk", - "android.frameworks.stats-V1-ndk", - "android.hardware.power-V1-ndk", - "android.hardware.thermal-V1-ndk", - "pixel-power-ext-V1-ndk", - "pixelatoms-cpp", - ], - static_libs: [ - "libpixelstats", - ], - export_shared_lib_headers: [ - "android.frameworks.stats-V1-ndk", - "pixelatoms-cpp", - ], - cflags: [ - "-Wall", - "-Werror", - "-Wextra", - "-Wunused", - ], - tidy: true, - tidy_checks: [ - "android-*", - "cert-*", - "clang-analyzer-security*", - ], - tidy_checks_as_errors: [ - "android-*", - "clang-analyzer-security*", - "cert-*", - ], + name: "android.hardware.thermal-service.pixel", + srcs: [ + "service.cpp", + "Thermal.cpp", + "thermal-helper.cpp", + "utils/thermal_throttling.cpp", + "utils/thermal_info.cpp", + "utils/thermal_files.cpp", + "utils/power_files.cpp", + "utils/powerhal_helper.cpp", + "utils/thermal_stats_helper.cpp", + "utils/thermal_watcher.cpp", + ], + vendor: true, + relative_install_path: "hw", + vintf_fragments: [ + "android.hardware.thermal-service.pixel.xml", + ], + init_rc: [ + "android.hardware.thermal-service.pixel.rc", + ], + shared_libs: [ + "libbase", + "libcutils", + "libjsoncpp", + "libutils", + "libnl", + "libbinder_ndk", + "android.frameworks.stats-V1-ndk", + "android.hardware.power-V1-ndk", + "android.hardware.thermal-V1-ndk", + "pixel-power-ext-V1-ndk", + "pixelatoms-cpp", + ], + static_libs: [ + "libpixelstats", + ], + export_shared_lib_headers: [ + "android.frameworks.stats-V1-ndk", + "pixelatoms-cpp", + ], + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + "-Wunused", + ], + tidy: true, + tidy_checks: [ + "android-*", + "cert-*", + "clang-analyzer-security*", + ], + tidy_checks_as_errors: [ + "android-*", + "clang-analyzer-security*", + "cert-*", + ], +} + +cc_test { + name: "libthermaltest", + vendor: true, + srcs: [ + "service.cpp", + "Thermal.cpp", + "thermal-helper.cpp", + "utils/thermal_throttling.cpp", + "utils/thermal_info.cpp", + "utils/thermal_files.cpp", + "utils/power_files.cpp", + "utils/powerhal_helper.cpp", + "utils/thermal_stats_helper.cpp", + "utils/thermal_watcher.cpp", + "tests/mock_thermal_helper.cpp", + "tests/thermal_looper_test.cpp", + ], + shared_libs: [ + "libbase", + "libcutils", + "libjsoncpp", + "libutils", + "libnl", + "liblog", + "libbinder_ndk", + "android.frameworks.stats-V1-ndk", + "android.hardware.power-V1-ndk", + "android.hardware.thermal-V1-ndk", + "pixel-power-ext-V1-ndk", + "pixelatoms-cpp", + ], + static_libs: [ + "libgmock", + "libpixelstats", + ], + test_suites: ["device-tests"], + require_root: true, } sh_binary { - name: "thermal_logd", - src: "init.thermal.logging.sh", - vendor: true, - init_rc: [ - "pixel-thermal-logd.rc", - ], + name: "thermal_logd", + src: "init.thermal.logging.sh", + vendor: true, + init_rc: [ + "pixel-thermal-logd.rc", + ], } sh_binary { - name: "thermal_symlinks", - src: "init.thermal.symlinks.sh", - vendor: true, - init_rc: [ - "pixel-thermal-symlinks.rc", - ], + name: "thermal_symlinks", + src: "init.thermal.symlinks.sh", + vendor: true, + init_rc: [ + "pixel-thermal-symlinks.rc", + ], } diff --git a/thermal/Thermal.cpp b/thermal/Thermal.cpp index e653f0b6..4b55ab96 100644 --- a/thermal/Thermal.cpp +++ b/thermal/Thermal.cpp @@ -50,9 +50,14 @@ bool interfacesEqual(const std::shared_ptr<::ndk::ICInterface> left, } // namespace -Thermal::Thermal() - : thermal_helper_( - std::bind(&Thermal::sendThermalChangedCallback, this, std::placeholders::_1)) {} +Thermal::Thermal() { + thermal_helper_ = std::make_shared<ThermalHelperImpl>( + std::bind(&Thermal::sendThermalChangedCallback, this, std::placeholders::_1)); +} + +Thermal::Thermal(const std::shared_ptr<ThermalHelper> &helper) { + thermal_helper_ = helper; +} ndk::ScopedAStatus Thermal::getTemperatures(std::vector<Temperature> *_aidl_return) { return getFilteredTemperatures(false, TemperatureType::UNKNOWN, _aidl_return); @@ -66,10 +71,10 @@ ndk::ScopedAStatus Thermal::getTemperaturesWithType(TemperatureType type, ndk::ScopedAStatus Thermal::getFilteredTemperatures(bool filterType, TemperatureType type, std::vector<Temperature> *_aidl_return) { *_aidl_return = {}; - if (!thermal_helper_.isInitializedOk()) { + if (!thermal_helper_->isInitializedOk()) { return initErrorStatus(); } - if (!thermal_helper_.fillCurrentTemperatures(filterType, false, type, _aidl_return)) { + if (!thermal_helper_->fillCurrentTemperatures(filterType, false, type, _aidl_return)) { return readErrorStatus(); } return ndk::ScopedAStatus::ok(); @@ -87,10 +92,10 @@ ndk::ScopedAStatus Thermal::getCoolingDevicesWithType(CoolingType type, ndk::ScopedAStatus Thermal::getFilteredCoolingDevices(bool filterType, CoolingType type, std::vector<CoolingDevice> *_aidl_return) { *_aidl_return = {}; - if (!thermal_helper_.isInitializedOk()) { + if (!thermal_helper_->isInitializedOk()) { return initErrorStatus(); } - if (!thermal_helper_.fillCurrentCoolingDevices(filterType, type, _aidl_return)) { + if (!thermal_helper_->fillCurrentCoolingDevices(filterType, type, _aidl_return)) { return readErrorStatus(); } return ndk::ScopedAStatus::ok(); @@ -110,10 +115,10 @@ ndk::ScopedAStatus Thermal::getTemperatureThresholdsWithType( ndk::ScopedAStatus Thermal::getFilteredTemperatureThresholds( bool filterType, TemperatureType type, std::vector<TemperatureThreshold> *_aidl_return) { *_aidl_return = {}; - if (!thermal_helper_.isInitializedOk()) { + if (!thermal_helper_->isInitializedOk()) { return initErrorStatus(); } - if (!thermal_helper_.fillTemperatureThresholds(filterType, type, _aidl_return)) { + if (!thermal_helper_->fillTemperatureThresholds(filterType, type, _aidl_return)) { return readErrorStatus(); } return ndk::ScopedAStatus::ok(); @@ -168,7 +173,7 @@ ndk::ScopedAStatus Thermal::registerThermalChangedCallback( return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Invalid nullptr callback"); } - if (!thermal_helper_.isInitializedOk()) { + if (!thermal_helper_->isInitializedOk()) { return initErrorStatus(); } std::lock_guard<std::mutex> _lock(thermal_callback_mutex_); @@ -184,14 +189,25 @@ ndk::ScopedAStatus Thermal::registerThermalChangedCallback( // Send notification right away after successful thermal callback registration std::function<void()> handler = [this, c, filterType, type]() { std::vector<Temperature> temperatures; - if (thermal_helper_.fillCurrentTemperatures(filterType, true, type, &temperatures)) { - for (const auto &t : temperatures) { - if (!filterType || t.type == type) { - LOG(INFO) << "Sending notification: " - << " Type: " << toString(t.type) << " Name: " << t.name - << " CurrentValue: " << t.value - << " ThrottlingStatus: " << toString(t.throttlingStatus); - c.callback->notifyThrottling(t); + if (thermal_helper_->fillCurrentTemperatures(filterType, true, type, &temperatures)) { + std::lock_guard<std::mutex> _lock(thermal_callback_mutex_); + auto it = std::find_if(callbacks_.begin(), callbacks_.end(), + [&](const CallbackSetting &cc) { + return interfacesEqual(c.callback, cc.callback); + }); + if (it != callbacks_.end()) { + if (AIBinder_isAlive(c.callback->asBinder().get())) { + for (const auto &t : temperatures) { + if (!filterType || t.type == type) { + LOG(INFO) << "Sending notification: " + << " Type: " << toString(t.type) << " Name: " << t.name + << " CurrentValue: " << t.value + << " ThrottlingStatus: " << toString(t.throttlingStatus); + c.callback->notifyThrottling(t); + } + } + } else { + callbacks_.erase(it); } } } @@ -227,7 +243,7 @@ void Thermal::sendThermalChangedCallback(const Temperature &t) { void Thermal::dumpVirtualSensorInfo(std::ostringstream *dump_buf) { *dump_buf << "getVirtualSensorInfo:" << std::endl; - const auto &map = thermal_helper_.GetSensorInfoMap(); + const auto &map = thermal_helper_->GetSensorInfoMap(); for (const auto &sensor_info_pair : map) { if (sensor_info_pair.second.virtual_sensor_info != nullptr) { *dump_buf << " Name: " << sensor_info_pair.first << std::endl; @@ -282,8 +298,8 @@ void Thermal::dumpVirtualSensorInfo(std::ostringstream *dump_buf) { void Thermal::dumpThrottlingInfo(std::ostringstream *dump_buf) { *dump_buf << "getThrottlingInfo:" << std::endl; - const auto &map = thermal_helper_.GetSensorInfoMap(); - const auto &thermal_throttling_status_map = thermal_helper_.GetThermalThrottlingStatusMap(); + const auto &map = thermal_helper_->GetSensorInfoMap(); + const auto &thermal_throttling_status_map = thermal_helper_->GetThermalThrottlingStatusMap(); for (const auto &name_info_pair : map) { if (name_info_pair.second.throttling_info == nullptr) { continue; @@ -343,9 +359,14 @@ void Thermal::dumpThrottlingInfo(std::ostringstream *dump_buf) { } *dump_buf << "]" << std::endl; } - *dump_buf << " Binded CDEV Info:" << std::endl; + const auto &profile = thermal_throttling_status_map.at(name_info_pair.first).profile; + *dump_buf << " Binded CDEV Info:" << (profile.empty() ? "default" : profile) + << std::endl; + for (const auto &binded_cdev_info_pair : - name_info_pair.second.throttling_info->binded_cdev_info_map) { + name_info_pair.second.throttling_info->profile_map.count(profile) + ? name_info_pair.second.throttling_info->profile_map.at(profile) + : name_info_pair.second.throttling_info->binded_cdev_info_map) { *dump_buf << " Cooling device name: " << binded_cdev_info_pair.first << std::endl; if (thermal_throttling_status_map.at(name_info_pair.first) .pid_power_budget_map.size()) { @@ -411,7 +432,7 @@ void Thermal::dumpThrottlingInfo(std::ostringstream *dump_buf) { } void Thermal::dumpThrottlingRequestStatus(std::ostringstream *dump_buf) { - const auto &thermal_throttling_status_map = thermal_helper_.GetThermalThrottlingStatusMap(); + const auto &thermal_throttling_status_map = thermal_helper_->GetThermalThrottlingStatusMap(); if (!thermal_throttling_status_map.size()) { return; } @@ -461,8 +482,8 @@ void Thermal::dumpThrottlingRequestStatus(std::ostringstream *dump_buf) { } void Thermal::dumpPowerRailInfo(std::ostringstream *dump_buf) { - const auto &power_rail_info_map = thermal_helper_.GetPowerRailInfoMap(); - const auto &power_status_map = thermal_helper_.GetPowerStatusMap(); + const auto &power_rail_info_map = thermal_helper_->GetPowerRailInfoMap(); + const auto &power_status_map = thermal_helper_->GetPowerStatusMap(); *dump_buf << "getPowerRailInfo:" << std::endl; for (const auto &power_rail_pair : power_rail_info_map) { @@ -540,7 +561,7 @@ void Thermal::dumpStatsRecord(std::ostringstream *dump_buf, const StatsRecord &s void Thermal::dumpThermalStats(std::ostringstream *dump_buf) { *dump_buf << "getThermalStatsInfo:" << std::endl; *dump_buf << " Sensor Temp Stats Info:" << std::endl; - const auto &sensor_temp_stats_map_ = thermal_helper_.GetSensorTempStatsSnapshot(); + const auto &sensor_temp_stats_map_ = thermal_helper_->GetSensorTempStatsSnapshot(); const std::string sensor_temp_stats_line_prefix(" "); for (const auto &sensor_temp_stats_pair : sensor_temp_stats_map_) { *dump_buf << " Sensor Name: " << sensor_temp_stats_pair.first << std::endl; @@ -571,7 +592,7 @@ void Thermal::dumpThermalStats(std::ostringstream *dump_buf) { } *dump_buf << " Sensor Cdev Request Stats Info:" << std::endl; const auto &sensor_cdev_request_stats_map_ = - thermal_helper_.GetSensorCoolingDeviceRequestStatsSnapshot(); + thermal_helper_->GetSensorCoolingDeviceRequestStatsSnapshot(); const std::string sensor_cdev_request_stats_line_prefix(" "); for (const auto &sensor_cdev_request_stats_pair : sensor_cdev_request_stats_map_) { *dump_buf << " Sensor Name: " << sensor_cdev_request_stats_pair.first << std::endl; @@ -603,10 +624,10 @@ void Thermal::dumpThermalStats(std::ostringstream *dump_buf) { void Thermal::dumpThermalData(int fd) { std::ostringstream dump_buf; - if (!thermal_helper_.isInitializedOk()) { + if (!thermal_helper_->isInitializedOk()) { dump_buf << "ThermalHAL not initialized properly." << std::endl; } else { - const auto &sensor_status_map = thermal_helper_.GetSensorStatusMap(); + const auto &sensor_status_map = thermal_helper_->GetSensorStatusMap(); { dump_buf << "getCachedTemperatures:" << std::endl; boot_clock::time_point now = boot_clock::now(); @@ -637,11 +658,11 @@ void Thermal::dumpThermalData(int fd) { } } { - const auto &map = thermal_helper_.GetSensorInfoMap(); + const auto &map = thermal_helper_->GetSensorInfoMap(); dump_buf << "getCurrentTemperatures:" << std::endl; Temperature temp_2_0; for (const auto &name_info_pair : map) { - thermal_helper_.readTemperature(name_info_pair.first, &temp_2_0, nullptr, true); + thermal_helper_->readTemperature(name_info_pair.first, &temp_2_0, nullptr, true); dump_buf << " Type: " << toString(temp_2_0.type) << " Name: " << name_info_pair.first << " CurrentValue: " << temp_2_0.value << " ThrottlingStatus: " << toString(temp_2_0.throttlingStatus) @@ -685,8 +706,8 @@ void Thermal::dumpThermalData(int fd) { { dump_buf << "getCurrentCoolingDevices:" << std::endl; std::vector<CoolingDevice> cooling_devices; - if (!thermal_helper_.fillCurrentCoolingDevices(false, CoolingType::CPU, - &cooling_devices)) { + if (!thermal_helper_->fillCurrentCoolingDevices(false, CoolingType::CPU, + &cooling_devices)) { dump_buf << " Failed to getCurrentCoolingDevices." << std::endl; } @@ -706,7 +727,7 @@ void Thermal::dumpThermalData(int fd) { { dump_buf << "sendCallback:" << std::endl; dump_buf << " Enabled List: "; - const auto &map = thermal_helper_.GetSensorInfoMap(); + const auto &map = thermal_helper_->GetSensorInfoMap(); for (const auto &name_info_pair : map) { if (name_info_pair.second.send_cb) { dump_buf << name_info_pair.first << " "; @@ -717,7 +738,7 @@ void Thermal::dumpThermalData(int fd) { { dump_buf << "sendPowerHint:" << std::endl; dump_buf << " Enabled List: "; - const auto &map = thermal_helper_.GetSensorInfoMap(); + const auto &map = thermal_helper_->GetSensorInfoMap(); for (const auto &name_info_pair : map) { if (name_info_pair.second.send_powerhint) { dump_buf << name_info_pair.first << " "; @@ -732,12 +753,12 @@ void Thermal::dumpThermalData(int fd) { dumpThermalStats(&dump_buf); { dump_buf << "getAIDLPowerHalInfo:" << std::endl; - dump_buf << " Exist: " << std::boolalpha << thermal_helper_.isAidlPowerHalExist() + dump_buf << " Exist: " << std::boolalpha << thermal_helper_->isAidlPowerHalExist() << std::endl; - dump_buf << " Connected: " << std::boolalpha << thermal_helper_.isPowerHalConnected() + dump_buf << " Connected: " << std::boolalpha << thermal_helper_->isPowerHalConnected() << std::endl; dump_buf << " Ext connected: " << std::boolalpha - << thermal_helper_.isPowerHalExtConnected() << std::endl; + << thermal_helper_->isPowerHalExtConnected() << std::endl; } } std::string buf = dump_buf.str(); @@ -755,18 +776,19 @@ binder_status_t Thermal::dump(int fd, const char **args, uint32_t numArgs) { if (std::string(args[0]) == "emul_temp") { return (numArgs != 3 || - !thermal_helper_.emulTemp(std::string(args[1]), std::strtod(args[2], nullptr))) + !thermal_helper_->emulTemp(std::string(args[1]), std::strtod(args[2], nullptr))) ? STATUS_BAD_VALUE : STATUS_OK; } else if (std::string(args[0]) == "emul_severity") { return (numArgs != 3 || - !thermal_helper_.emulSeverity(std::string(args[1]), - static_cast<int>(std::strtol(args[2], nullptr, 10)))) + !thermal_helper_->emulSeverity(std::string(args[1]), + static_cast<int>(std::strtol(args[2], nullptr, 10)))) ? STATUS_BAD_VALUE : STATUS_OK; } else if (std::string(args[0]) == "emul_clear") { - return (numArgs != 2 || !thermal_helper_.emulClear(std::string(args[1]))) ? STATUS_BAD_VALUE - : STATUS_OK; + return (numArgs != 2 || !thermal_helper_->emulClear(std::string(args[1]))) + ? STATUS_BAD_VALUE + : STATUS_OK; } return STATUS_BAD_VALUE; } @@ -777,14 +799,25 @@ void Thermal::Looper::addEvent(const Thermal::Looper::Event &e) { cv_.notify_all(); } +Thermal::Looper::~Looper() { + { + std::unique_lock<std::mutex> lock(mutex_); + aborted_ = true; + } + cv_.notify_one(); + thread_.join(); +} + void Thermal::Looper::loop() { - while (true) { + while (!aborted_) { std::unique_lock<std::mutex> lock(mutex_); - cv_.wait(lock, [&] { return !events_.empty(); }); - Event event = events_.front(); - events_.pop(); - lock.unlock(); - event.handler(); + cv_.wait(lock, [&] { return aborted_ || !events_.empty(); }); + if (!aborted_ && !events_.empty()) { + Event event = events_.front(); + events_.pop(); + lock.unlock(); + event.handler(); + } } } diff --git a/thermal/Thermal.h b/thermal/Thermal.h index 74449c4e..f8f9c63a 100644 --- a/thermal/Thermal.h +++ b/thermal/Thermal.h @@ -41,6 +41,7 @@ struct CallbackSetting { class Thermal : public BnThermal { public: Thermal(); + explicit Thermal(const std::shared_ptr<ThermalHelper> &helper); ~Thermal() = default; ndk::ScopedAStatus getTemperatures(std::vector<Temperature> *_aidl_return) override; ndk::ScopedAStatus getTemperaturesWithType(TemperatureType type, @@ -77,6 +78,8 @@ class Thermal : public BnThermal { Looper() { thread_ = std::thread([&] { loop(); }); } + ~Looper(); + void addEvent(const Event &e); private: @@ -84,11 +87,12 @@ class Thermal : public BnThermal { std::queue<Event> events_; std::mutex mutex_; std::thread thread_; + bool aborted_; void loop(); }; - ThermalHelper thermal_helper_; + std::shared_ptr<ThermalHelper> thermal_helper_; std::mutex thermal_callback_mutex_; std::vector<CallbackSetting> callbacks_; Looper looper_; diff --git a/thermal/tests/mock_thermal_helper.cpp b/thermal/tests/mock_thermal_helper.cpp new file mode 100644 index 00000000..358371d4 --- /dev/null +++ b/thermal/tests/mock_thermal_helper.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2023 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. + */ + +#include "mock_thermal_helper.h" + +namespace aidl::android::hardware::thermal::implementation { + +MockThermalHelper::MockThermalHelper() = default; +MockThermalHelper::~MockThermalHelper() = default; + +} // namespace aidl::android::hardware::thermal::implementation diff --git a/thermal/tests/mock_thermal_helper.h b/thermal/tests/mock_thermal_helper.h new file mode 100644 index 00000000..43ff3286 --- /dev/null +++ b/thermal/tests/mock_thermal_helper.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023 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. + */ + +#include <aidl/android/hardware/thermal/IThermal.h> +#include <gmock/gmock.h> +#include <log/log.h> + +#include <unordered_map> + +#include "thermal-helper.h" + +namespace aidl::android::hardware::thermal::implementation { + +class MockThermalHelper : public ThermalHelper { + public: + MockThermalHelper(); + ~MockThermalHelper() override; + MOCK_METHOD(bool, fillCurrentTemperatures, + (bool, bool, TemperatureType, std::vector<Temperature> *), (override)); + MOCK_METHOD(bool, fillTemperatureThresholds, + (bool, TemperatureType, std::vector<TemperatureThreshold> *), (const, override)); + MOCK_METHOD(bool, fillCurrentCoolingDevices, (bool, CoolingType, std::vector<CoolingDevice> *), + (const, override)); + MOCK_METHOD(bool, emulTemp, (std::string_view, const float), (override)); + MOCK_METHOD(bool, emulSeverity, (std::string_view, const int), (override)); + MOCK_METHOD(bool, emulClear, (std::string_view), (override)); + MOCK_METHOD(bool, isInitializedOk, (), (const, override)); + MOCK_METHOD(bool, readTemperature, + (std::string_view, Temperature *out, + (std::pair<ThrottlingSeverity, ThrottlingSeverity> *), const bool), + (override)); + MOCK_METHOD(bool, readTemperatureThreshold, (std::string_view, TemperatureThreshold *), + (const, override)); + MOCK_METHOD(bool, readCoolingDevice, (std::string_view, CoolingDevice *), (const, override)); + MOCK_METHOD((const std::unordered_map<std::string, SensorInfo> &), GetSensorInfoMap, (), + (const, override)); + MOCK_METHOD((const std::unordered_map<std::string, CdevInfo> &), GetCdevInfoMap, (), + (const, override)); + MOCK_METHOD((const std::unordered_map<std::string, SensorStatus> &), GetSensorStatusMap, (), + (const, override)); + MOCK_METHOD((const std::unordered_map<std::string, ThermalThrottlingStatus> &), + GetThermalThrottlingStatusMap, (), (const, override)); + MOCK_METHOD((const std::unordered_map<std::string, PowerRailInfo> &), GetPowerRailInfoMap, (), + (const, override)); + MOCK_METHOD((const std::unordered_map<std::string, PowerStatus> &), GetPowerStatusMap, (), + (const, override)); + MOCK_METHOD((const std::unordered_map<std::string, SensorTempStats>), + GetSensorTempStatsSnapshot, (), (override)); + MOCK_METHOD((const std::unordered_map<std::string, + std::unordered_map<std::string, ThermalStats<int>>>), + GetSensorCoolingDeviceRequestStatsSnapshot, (), (override)); + MOCK_METHOD(bool, isAidlPowerHalExist, (), (override)); + MOCK_METHOD(bool, isPowerHalConnected, (), (override)); + MOCK_METHOD(bool, isPowerHalExtConnected, (), (override)); +}; + +} // namespace aidl::android::hardware::thermal::implementation diff --git a/thermal/tests/thermal_looper_test.cpp b/thermal/tests/thermal_looper_test.cpp new file mode 100644 index 00000000..65f13d13 --- /dev/null +++ b/thermal/tests/thermal_looper_test.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2023 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. + */ + +#include <aidl/android/hardware/thermal/BnThermalChangedCallback.h> +#include <log/log.h> + +#include "Thermal.h" +#include "mock_thermal_helper.h" + +namespace aidl::android::hardware::thermal::implementation { + +class ThermalLooperTest : public testing::Test { + protected: + void SetUp() override { + ON_CALL(*helper, isInitializedOk).WillByDefault(testing::Return(true)); + } + + std::shared_ptr<testing::NiceMock<MockThermalHelper>> helper = + std::make_shared<testing::NiceMock<MockThermalHelper>>(); + std::shared_ptr<Thermal> thermal = ndk::SharedRefBase::make<Thermal>(helper); +}; + +class TestCallback : public BnThermalChangedCallback { + public: + ndk::ScopedAStatus notifyThrottling(const Temperature &t) override { + std::lock_guard<std::mutex> lock_guard(mMutex); + mTemperatures.emplace_back(t); + return ndk::ScopedAStatus::ok(); + } + + std::vector<Temperature> getTemperatures() { + std::lock_guard<std::mutex> lock_guard(mMutex); + return mTemperatures; + } + + void clear() { + std::lock_guard<std::mutex> lock_guard(mMutex); + mTemperatures.clear(); + } + + private: + std::vector<Temperature> mTemperatures; + std::mutex mMutex; +}; + +TEST_F(ThermalLooperTest, AsyncCallbackTest) { + Temperature t1; + t1.type = TemperatureType::SKIN; + Temperature t2; + t2.type = TemperatureType::UNKNOWN; + ON_CALL(*helper, fillCurrentTemperatures) + .WillByDefault([this, t1, t2](bool, bool, TemperatureType, + std::vector<Temperature> *temperatures) { + std::vector<Temperature> ret = {t1, t2}; + *temperatures = ret; + sleep(1); + return true; + }); + std::shared_ptr<TestCallback> callback = ndk::SharedRefBase::make<TestCallback>(); + std::shared_ptr<TestCallback> callbackWithType = ndk::SharedRefBase::make<TestCallback>(); + + // if callback immediately unregistered, no async callback should be scheduled + ASSERT_TRUE(thermal->registerThermalChangedCallback(callback).isOk()); + ASSERT_TRUE( + thermal->registerThermalChangedCallbackWithType(callbackWithType, TemperatureType::SKIN) + .isOk()); + ASSERT_TRUE(thermal->unregisterThermalChangedCallback(callback).isOk()); + ASSERT_TRUE(thermal->unregisterThermalChangedCallback(callbackWithType).isOk()); + sleep(3); + ASSERT_TRUE(callback->getTemperatures().empty()); + ASSERT_TRUE(callbackWithType->getTemperatures().empty()); + + // otherwise, async callback should be scheduled if registered + ASSERT_TRUE(thermal->registerThermalChangedCallback(callback).isOk()); + ASSERT_TRUE( + thermal->registerThermalChangedCallbackWithType(callbackWithType, TemperatureType::SKIN) + .isOk()); + sleep(3); + ASSERT_THAT(callback->getTemperatures(), testing::UnorderedElementsAreArray({t1, t2})); + ASSERT_THAT(callbackWithType->getTemperatures(), testing::UnorderedElementsAreArray({t1})); +} + +} // namespace aidl::android::hardware::thermal::implementation diff --git a/thermal/thermal-helper.cpp b/thermal/thermal-helper.cpp index d7411bc3..dc4a599c 100644 --- a/thermal/thermal-helper.cpp +++ b/thermal/thermal-helper.cpp @@ -92,14 +92,31 @@ std::unordered_map<std::string, std::string> parseThermalPathMap(std::string_vie } // namespace +// If the cdev_ceiling is higher than CDEV max_state, cap the cdev_ceiling to max_state. +void ThermalHelperImpl::maxCoolingRequestCheck( + std::unordered_map<std::string, BindedCdevInfo> *binded_cdev_info_map) { + for (auto &binded_cdev_info_pair : *binded_cdev_info_map) { + const auto &cdev_info = cooling_device_info_map_.at(binded_cdev_info_pair.first); + for (auto &cdev_ceiling : binded_cdev_info_pair.second.cdev_ceiling) { + if (cdev_ceiling > cdev_info.max_state) { + if (cdev_ceiling != std::numeric_limits<int>::max()) { + LOG(ERROR) << binded_cdev_info_pair.first << " cdev_ceiling:" << cdev_ceiling + << " is higher than max state:" << cdev_info.max_state; + } + cdev_ceiling = cdev_info.max_state; + } + } + } +} + /* * Populate the sensor_name_to_file_map_ map by walking through the file tree, * reading the type file and assigning the temp file path to the map. If we do * not succeed, abort. */ -ThermalHelper::ThermalHelper(const NotificationCallback &cb) - : thermal_watcher_(new ThermalWatcher( - std::bind(&ThermalHelper::thermalWatcherCallbackFunc, this, std::placeholders::_1))), +ThermalHelperImpl::ThermalHelperImpl(const NotificationCallback &cb) + : thermal_watcher_(new ThermalWatcher(std::bind(&ThermalHelperImpl::thermalWatcherCallbackFunc, + this, std::placeholders::_1))), cb_(cb) { const std::string config_path = "/vendor/etc/" + @@ -145,12 +162,11 @@ ThermalHelper::ThermalHelper(const NotificationCallback &cb) LOG(FATAL) << "Failed to initialize thermal stats"; } - for (auto const &name_status_pair : sensor_info_map_) { + for (auto &name_status_pair : sensor_info_map_) { sensor_status_map_[name_status_pair.first] = { .severity = ThrottlingSeverity::NONE, .prev_hot_severity = ThrottlingSeverity::NONE, .prev_cold_severity = ThrottlingSeverity::NONE, - .prev_hint_severity = ThrottlingSeverity::NONE, .last_update_time = boot_clock::time_point::min(), .thermal_cached = {NAN, boot_clock::time_point::min()}, .emul_setting = nullptr, @@ -165,22 +181,13 @@ ThermalHelper::ThermalHelper(const NotificationCallback &cb) break; } - // Update cooling device max state - for (auto &binded_cdev_info_pair : - name_status_pair.second.throttling_info->binded_cdev_info_map) { - const auto &cdev_info = cooling_device_info_map_.at(binded_cdev_info_pair.first); - - for (auto &cdev_ceiling : binded_cdev_info_pair.second.cdev_ceiling) { - if (cdev_ceiling > cdev_info.max_state) { - if (cdev_ceiling != std::numeric_limits<int>::max()) { - LOG(WARNING) << "Sensor " << name_status_pair.first << "'s " - << binded_cdev_info_pair.first - << " cdev_ceiling:" << cdev_ceiling - << " is higher than max state:" << cdev_info.max_state; - } - cdev_ceiling = cdev_info.max_state; - } - } + // Update cooling device max state for default mode + maxCoolingRequestCheck(&name_status_pair.second.throttling_info->binded_cdev_info_map); + + // Update cooling device max state for each profile mode + for (auto &cdev_throttling_profile_pair : + name_status_pair.second.throttling_info->profile_map) { + maxCoolingRequestCheck(&cdev_throttling_profile_pair.second); } } // Check the virtual sensor settings are valid @@ -222,10 +229,10 @@ ThermalHelper::ThermalHelper(const NotificationCallback &cb) } } - if (!connectToPowerHal()) { + if (!power_hal_service_.connect()) { LOG(ERROR) << "Fail to connect to Power Hal"; } else { - updateSupportedPowerHints(); + power_hal_service_.updateSupportedPowerHints(sensor_info_map_); } if (thermal_throttling_disabled) { @@ -260,12 +267,6 @@ ThermalHelper::ThermalHelper(const NotificationCallback &cb) if (!is_initialized_) { LOG(FATAL) << "ThermalHAL could not start watching thread properly."; } - - if (!connectToPowerHal()) { - LOG(ERROR) << "Fail to connect to Power Hal"; - } else { - updateSupportedPowerHints(); - } } bool getThermalZoneTypeById(int tz_id, std::string *type) { @@ -285,7 +286,7 @@ bool getThermalZoneTypeById(int tz_id, std::string *type) { return true; } -bool ThermalHelper::emulTemp(std::string_view target_sensor, const float value) { +bool ThermalHelperImpl::emulTemp(std::string_view target_sensor, const float value) { LOG(INFO) << "Set " << target_sensor.data() << " emul_temp " << "to " << value; @@ -303,7 +304,7 @@ bool ThermalHelper::emulTemp(std::string_view target_sensor, const float value) return true; } -bool ThermalHelper::emulSeverity(std::string_view target_sensor, const int severity) { +bool ThermalHelperImpl::emulSeverity(std::string_view target_sensor, const int severity) { LOG(INFO) << "Set " << target_sensor.data() << " emul_severity " << "to " << severity; @@ -326,7 +327,7 @@ bool ThermalHelper::emulSeverity(std::string_view target_sensor, const int sever return true; } -bool ThermalHelper::emulClear(std::string_view target_sensor) { +bool ThermalHelperImpl::emulClear(std::string_view target_sensor) { LOG(INFO) << "Clear " << target_sensor.data() << " emulation settings"; std::lock_guard<std::shared_mutex> _lock(sensor_status_map_mutex_); @@ -347,7 +348,8 @@ bool ThermalHelper::emulClear(std::string_view target_sensor) { return true; } -bool ThermalHelper::readCoolingDevice(std::string_view cooling_device, CoolingDevice *out) const { +bool ThermalHelperImpl::readCoolingDevice(std::string_view cooling_device, + CoolingDevice *out) const { // Read the file. If the file can't be read temp will be empty string. std::string data; @@ -366,7 +368,7 @@ bool ThermalHelper::readCoolingDevice(std::string_view cooling_device, CoolingDe return true; } -bool ThermalHelper::readTemperature( +bool ThermalHelperImpl::readTemperature( std::string_view sensor_name, Temperature *out, std::pair<ThrottlingSeverity, ThrottlingSeverity> *throttling_status, const bool force_no_cache) { @@ -375,8 +377,8 @@ bool ThermalHelper::readTemperature( std::map<std::string, float> sensor_log_map; auto &sensor_status = sensor_status_map_.at(sensor_name.data()); - if (!readThermalSensor(sensor_name, &temp, force_no_cache, &sensor_log_map)) { - LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name; + if (!readThermalSensor(sensor_name, &temp, force_no_cache, &sensor_log_map) || + std::isnan(temp)) { return false; } @@ -428,8 +430,8 @@ bool ThermalHelper::readTemperature( return true; } -bool ThermalHelper::readTemperatureThreshold(std::string_view sensor_name, - TemperatureThreshold *out) const { +bool ThermalHelperImpl::readTemperatureThreshold(std::string_view sensor_name, + TemperatureThreshold *out) const { // Read the file. If the file can't be read temp will be empty string. std::string temp; std::string path; @@ -450,7 +452,7 @@ bool ThermalHelper::readTemperatureThreshold(std::string_view sensor_name, return true; } -void ThermalHelper::updateCoolingDevices(const std::vector<std::string> &updated_cdev) { +void ThermalHelperImpl::updateCoolingDevices(const std::vector<std::string> &updated_cdev) { int max_state; for (const auto &target_cdev : updated_cdev) { @@ -466,7 +468,7 @@ void ThermalHelper::updateCoolingDevices(const std::vector<std::string> &updated } } -std::pair<ThrottlingSeverity, ThrottlingSeverity> ThermalHelper::getSeverityFromThresholds( +std::pair<ThrottlingSeverity, ThrottlingSeverity> ThermalHelperImpl::getSeverityFromThresholds( const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds, const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis, ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity, @@ -507,8 +509,8 @@ std::pair<ThrottlingSeverity, ThrottlingSeverity> ThermalHelper::getSeverityFrom return std::make_pair(ret_hot, ret_cold); } -bool ThermalHelper::isSubSensorValid(std::string_view sensor_data, - const SensorFusionType sensor_fusion_type) { +bool ThermalHelperImpl::isSubSensorValid(std::string_view sensor_data, + const SensorFusionType sensor_fusion_type) { switch (sensor_fusion_type) { case SensorFusionType::SENSOR: if (!sensor_info_map_.count(sensor_data.data())) { @@ -528,7 +530,7 @@ bool ThermalHelper::isSubSensorValid(std::string_view sensor_data, return true; } -void ThermalHelper::clearAllThrottling(void) { +void ThermalHelperImpl::clearAllThrottling(void) { // Clear the CDEV request for (const auto &cdev_info_pair : cooling_device_info_map_) { cooling_devices_.writeCdevFile(cdev_info_pair.first, "0"); @@ -558,7 +560,7 @@ void ThermalHelper::clearAllThrottling(void) { } } -bool ThermalHelper::initializeSensorMap( +bool ThermalHelperImpl::initializeSensorMap( const std::unordered_map<std::string, std::string> &path_map) { for (const auto &sensor_info_pair : sensor_info_map_) { std::string_view sensor_name = sensor_info_pair.first; @@ -586,7 +588,7 @@ bool ThermalHelper::initializeSensorMap( return true; } -bool ThermalHelper::initializeCoolingDevices( +bool ThermalHelperImpl::initializeCoolingDevices( const std::unordered_map<std::string, std::string> &path_map) { for (auto &cooling_device_info_pair : cooling_device_info_map_) { std::string cooling_device_name = cooling_device_info_pair.first; @@ -674,14 +676,14 @@ bool ThermalHelper::initializeCoolingDevices( return true; } -void ThermalHelper::setMinTimeout(SensorInfo *sensor_info) { +void ThermalHelperImpl::setMinTimeout(SensorInfo *sensor_info) { sensor_info->polling_delay = kMinPollIntervalMs; sensor_info->passive_delay = kMinPollIntervalMs; } -void ThermalHelper::initializeTrip(const std::unordered_map<std::string, std::string> &path_map, - std::set<std::string> *monitored_sensors, - bool thermal_genl_enabled) { +void ThermalHelperImpl::initializeTrip(const std::unordered_map<std::string, std::string> &path_map, + std::set<std::string> *monitored_sensors, + bool thermal_genl_enabled) { for (auto &sensor_info : sensor_info_map_) { if (!sensor_info.second.is_watch || (sensor_info.second.virtual_sensor_info != nullptr)) { continue; @@ -754,9 +756,9 @@ void ThermalHelper::initializeTrip(const std::unordered_map<std::string, std::st } } -bool ThermalHelper::fillCurrentTemperatures(bool filterType, bool filterCallback, - TemperatureType type, - std::vector<Temperature> *temperatures) { +bool ThermalHelperImpl::fillCurrentTemperatures(bool filterType, bool filterCallback, + TemperatureType type, + std::vector<Temperature> *temperatures) { std::vector<Temperature> ret; for (const auto &name_info_pair : sensor_info_map_) { Temperature temp; @@ -780,8 +782,9 @@ bool ThermalHelper::fillCurrentTemperatures(bool filterType, bool filterCallback return ret.size() > 0; } -bool ThermalHelper::fillTemperatureThresholds(bool filterType, TemperatureType type, - std::vector<TemperatureThreshold> *thresholds) const { +bool ThermalHelperImpl::fillTemperatureThresholds( + bool filterType, TemperatureType type, + std::vector<TemperatureThreshold> *thresholds) const { std::vector<TemperatureThreshold> ret; for (const auto &name_info_pair : sensor_info_map_) { TemperatureThreshold temp; @@ -803,8 +806,8 @@ bool ThermalHelper::fillTemperatureThresholds(bool filterType, TemperatureType t return ret.size() > 0; } -bool ThermalHelper::fillCurrentCoolingDevices(bool filterType, CoolingType type, - std::vector<CoolingDevice> *cooling_devices) const { +bool ThermalHelperImpl::fillCurrentCoolingDevices( + bool filterType, CoolingType type, std::vector<CoolingDevice> *cooling_devices) const { std::vector<CoolingDevice> ret; for (const auto &name_info_pair : cooling_device_info_map_) { CoolingDevice value; @@ -822,9 +825,9 @@ bool ThermalHelper::fillCurrentCoolingDevices(bool filterType, CoolingType type, return ret.size() > 0; } -bool ThermalHelper::readDataByType(std::string_view sensor_data, float *reading_value, - const SensorFusionType type, const bool force_no_cache, - std::map<std::string, float> *sensor_log_map) { +bool ThermalHelperImpl::readDataByType(std::string_view sensor_data, float *reading_value, + const SensorFusionType type, const bool force_no_cache, + std::map<std::string, float> *sensor_log_map) { switch (type) { case SensorFusionType::SENSOR: if (!readThermalSensor(sensor_data.data(), reading_value, force_no_cache, @@ -837,19 +840,24 @@ bool ThermalHelper::readDataByType(std::string_view sensor_data, float *reading_ *reading_value = GetPowerStatusMap().at(sensor_data.data()).last_updated_avg_power; if (std::isnan(*reading_value)) { LOG(INFO) << "Power data " << sensor_data.data() << " is under collecting"; - return false; + return true; } (*sensor_log_map)[sensor_data.data()] = *reading_value; break; + case SensorFusionType::CONSTANT: + *reading_value = std::atof(sensor_data.data()); + break; default: break; } return true; } -bool ThermalHelper::readThermalSensor(std::string_view sensor_name, float *temp, - const bool force_no_cache, - std::map<std::string, float> *sensor_log_map) { +constexpr int kTranTimeoutParam = 2; + +bool ThermalHelperImpl::readThermalSensor(std::string_view sensor_name, float *temp, + const bool force_no_cache, + std::map<std::string, float> *sensor_log_map) { float temp_val = 0.0; std::string file_reading; boot_clock::time_point now = boot_clock::now(); @@ -872,11 +880,13 @@ bool ThermalHelper::readThermalSensor(std::string_view sensor_name, float *temp, } } + const auto since_last_update = std::chrono::duration_cast<std::chrono::milliseconds>( + now - sensor_status.thermal_cached.timestamp); + // Check if thermal data need to be read from cache if (!force_no_cache && (sensor_status.thermal_cached.timestamp != boot_clock::time_point::min()) && - (std::chrono::duration_cast<std::chrono::milliseconds>( - now - sensor_status.thermal_cached.timestamp) < sensor_info.time_resolution) && + (since_last_update < sensor_info.time_resolution) && !isnan(sensor_status.thermal_cached.temp)) { *temp = sensor_status.thermal_cached.temp; (*sensor_log_map)[sensor_name.data()] = *temp; @@ -886,11 +896,8 @@ bool ThermalHelper::readThermalSensor(std::string_view sensor_name, float *temp, // Reading thermal sensor according to it's composition if (sensor_info.virtual_sensor_info == nullptr) { - if (!thermal_sensors_.readThermalFile(sensor_name.data(), &file_reading)) { - return false; - } - - if (file_reading.empty()) { + if (!thermal_sensors_.readThermalFile(sensor_name.data(), &file_reading) || + file_reading.empty()) { LOG(ERROR) << "failed to read sensor: " << sensor_name; return false; } @@ -904,11 +911,23 @@ bool ThermalHelper::readThermalSensor(std::string_view sensor_name, float *temp, force_no_cache, sensor_log_map)) { LOG(ERROR) << "Failed to read " << sensor_name.data() << "'s linked sensor " << sensor_info.virtual_sensor_info->linked_sensors[i]; + return false; } - if (std::isnan(sensor_info.virtual_sensor_info->coefficients[i])) { + + float coefficient = 0.0; + if (!readDataByType(sensor_info.virtual_sensor_info->coefficients[i], &coefficient, + sensor_info.virtual_sensor_info->coefficients_type[i], + force_no_cache, sensor_log_map)) { + LOG(ERROR) << "Failed to read " << sensor_name.data() << "'s coefficient " + << sensor_info.virtual_sensor_info->coefficients[i]; return false; } - float coefficient = sensor_info.virtual_sensor_info->coefficients[i]; + + if (std::isnan(sensor_reading) || std::isnan(coefficient)) { + LOG(INFO) << sensor_name << " data is under collecting"; + return true; + } + switch (sensor_info.virtual_sensor_info->formula) { case FormulaOption::COUNT_THRESHOLD: if ((coefficient < 0 && sensor_reading < -coefficient) || @@ -936,6 +955,13 @@ bool ThermalHelper::readThermalSensor(std::string_view sensor_name, float *temp, } *temp = (temp_val + sensor_info.virtual_sensor_info->offset); } + + if (!isnan(sensor_info.step_ratio) && !isnan(sensor_status.thermal_cached.temp) && + since_last_update < sensor_info.passive_delay * kTranTimeoutParam) { + *temp = (sensor_info.step_ratio * *temp + + (1 - sensor_info.step_ratio) * sensor_status.thermal_cached.temp); + } + (*sensor_log_map)[sensor_name.data()] = *temp; ATRACE_INT(sensor_name.data(), static_cast<int>(*temp)); @@ -951,7 +977,7 @@ bool ThermalHelper::readThermalSensor(std::string_view sensor_name, float *temp, // This is called in the different thread context and will update sensor_status // uevent_sensors is the set of sensors which trigger uevent from thermal core driver. -std::chrono::milliseconds ThermalHelper::thermalWatcherCallbackFunc( +std::chrono::milliseconds ThermalHelperImpl::thermalWatcherCallbackFunc( const std::set<std::string> &uevent_sensors) { std::vector<Temperature> temps; std::vector<std::string> cooling_devices_to_update; @@ -1109,8 +1135,8 @@ std::chrono::milliseconds ThermalHelper::thermalWatcherCallbackFunc( cb_(t); } - if (sensor_info_map_.at(t.name).send_powerhint && isAidlPowerHalExist()) { - sendPowerExtHint(t); + if (sensor_info_map_.at(t.name).send_powerhint) { + power_hal_service_.sendPowerExtHint(t); } } } @@ -1120,59 +1146,15 @@ std::chrono::milliseconds ThermalHelper::thermalWatcherCallbackFunc( LOG(ERROR) << "Failed to report " << count_failed_reporting << " thermal stats"; } - return min_sleep_ms; -} - -bool ThermalHelper::connectToPowerHal() { - return power_hal_service_.connect(); -} - -void ThermalHelper::updateSupportedPowerHints() { - for (auto const &name_status_pair : sensor_info_map_) { - if (!(name_status_pair.second.send_powerhint)) { - continue; - } - ThrottlingSeverity current_severity = ThrottlingSeverity::NONE; - for (const auto &severity : ::ndk::enum_range<ThrottlingSeverity>()) { - if (severity == ThrottlingSeverity::NONE) { - supported_powerhint_map_[name_status_pair.first][ThrottlingSeverity::NONE] = - ThrottlingSeverity::NONE; - continue; - } - - bool isSupported = false; - ndk::ScopedAStatus isSupportedResult; - - if (power_hal_service_.isPowerHalExtConnected()) { - isSupported = power_hal_service_.isModeSupported(name_status_pair.first, severity); - } - if (isSupported) - current_severity = severity; - supported_powerhint_map_[name_status_pair.first][severity] = current_severity; - } - } -} - -void ThermalHelper::sendPowerExtHint(const Temperature &t) { - ATRACE_CALL(); - std::lock_guard<std::shared_mutex> lock(sensor_status_map_mutex_); - ThrottlingSeverity prev_hint_severity; - prev_hint_severity = sensor_status_map_.at(t.name).prev_hint_severity; - ThrottlingSeverity current_hint_severity = supported_powerhint_map_[t.name][t.throttlingStatus]; - - if (prev_hint_severity == current_hint_severity) - return; - - if (prev_hint_severity != ThrottlingSeverity::NONE) { - power_hal_service_.setMode(t.name, prev_hint_severity, false); - } - - if (current_hint_severity != ThrottlingSeverity::NONE) { - power_hal_service_.setMode(t.name, current_hint_severity, true); + const auto since_last_power_log_ms = std::chrono::duration_cast<std::chrono::milliseconds>( + now - power_files_.GetPrevPowerLogTime()); + if (since_last_power_log_ms >= kPowerLogIntervalMs) { + power_files_.logPowerStatus(now); } - sensor_status_map_[t.name].prev_hint_severity = current_hint_severity; + return min_sleep_ms; } + } // namespace implementation } // namespace thermal } // namespace hardware diff --git a/thermal/thermal-helper.h b/thermal/thermal-helper.h index 3b790e3e..6ae13c43 100644 --- a/thermal/thermal-helper.h +++ b/thermal/thermal-helper.h @@ -65,7 +65,6 @@ struct SensorStatus { ThrottlingSeverity severity; ThrottlingSeverity prev_hot_severity; ThrottlingSeverity prev_cold_severity; - ThrottlingSeverity prev_hint_severity; boot_clock::time_point last_update_time; ThermalSample thermal_cached; std::unique_ptr<EmulSetting> emul_setting; @@ -73,77 +72,112 @@ struct SensorStatus { class ThermalHelper { public: - explicit ThermalHelper(const NotificationCallback &cb); - ~ThermalHelper() = default; + virtual ~ThermalHelper() = default; + virtual bool fillCurrentTemperatures(bool filterType, bool filterCallback, TemperatureType type, + std::vector<Temperature> *temperatures) = 0; + virtual bool fillTemperatureThresholds(bool filterType, TemperatureType type, + std::vector<TemperatureThreshold> *thresholds) const = 0; + virtual bool fillCurrentCoolingDevices(bool filterType, CoolingType type, + std::vector<CoolingDevice> *coolingdevices) const = 0; + virtual bool emulTemp(std::string_view target_sensor, const float temp) = 0; + virtual bool emulSeverity(std::string_view target_sensor, const int severity) = 0; + virtual bool emulClear(std::string_view target_sensor) = 0; + virtual bool isInitializedOk() const = 0; + virtual bool readTemperature( + std::string_view sensor_name, Temperature *out, + std::pair<ThrottlingSeverity, ThrottlingSeverity> *throtting_status = nullptr, + const bool force_sysfs = false) = 0; + virtual bool readTemperatureThreshold(std::string_view sensor_name, + TemperatureThreshold *out) const = 0; + virtual bool readCoolingDevice(std::string_view cooling_device, CoolingDevice *out) const = 0; + virtual const std::unordered_map<std::string, SensorInfo> &GetSensorInfoMap() const = 0; + virtual const std::unordered_map<std::string, CdevInfo> &GetCdevInfoMap() const = 0; + virtual const std::unordered_map<std::string, SensorStatus> &GetSensorStatusMap() const = 0; + virtual const std::unordered_map<std::string, ThermalThrottlingStatus> & + GetThermalThrottlingStatusMap() const = 0; + virtual const std::unordered_map<std::string, PowerRailInfo> &GetPowerRailInfoMap() const = 0; + virtual const std::unordered_map<std::string, PowerStatus> &GetPowerStatusMap() const = 0; + virtual const std::unordered_map<std::string, SensorTempStats> GetSensorTempStatsSnapshot() = 0; + virtual const std::unordered_map<std::string, + std::unordered_map<std::string, ThermalStats<int>>> + GetSensorCoolingDeviceRequestStatsSnapshot() = 0; + virtual bool isAidlPowerHalExist() = 0; + virtual bool isPowerHalConnected() = 0; + virtual bool isPowerHalExtConnected() = 0; +}; + +class ThermalHelperImpl : public ThermalHelper { + public: + explicit ThermalHelperImpl(const NotificationCallback &cb); + ~ThermalHelperImpl() override = default; bool fillCurrentTemperatures(bool filterType, bool filterCallback, TemperatureType type, - std::vector<Temperature> *temperatures); + std::vector<Temperature> *temperatures) override; bool fillTemperatureThresholds(bool filterType, TemperatureType type, - std::vector<TemperatureThreshold> *thresholds) const; + std::vector<TemperatureThreshold> *thresholds) const override; bool fillCurrentCoolingDevices(bool filterType, CoolingType type, - std::vector<CoolingDevice> *coolingdevices) const; - bool emulTemp(std::string_view target_sensor, const float temp); - bool emulSeverity(std::string_view target_sensor, const int severity); - bool emulClear(std::string_view target_sensor); + std::vector<CoolingDevice> *coolingdevices) const override; + bool emulTemp(std::string_view target_sensor, const float temp) override; + bool emulSeverity(std::string_view target_sensor, const int severity) override; + bool emulClear(std::string_view target_sensor) override; // Disallow copy and assign. - ThermalHelper(const ThermalHelper &) = delete; - void operator=(const ThermalHelper &) = delete; + ThermalHelperImpl(const ThermalHelperImpl &) = delete; + void operator=(const ThermalHelperImpl &) = delete; - bool isInitializedOk() const { return is_initialized_; } + bool isInitializedOk() const override { return is_initialized_; } // Read the temperature of a single sensor. - bool readTemperature(std::string_view sensor_name, Temperature *out); bool readTemperature( std::string_view sensor_name, Temperature *out, std::pair<ThrottlingSeverity, ThrottlingSeverity> *throtting_status = nullptr, - const bool force_sysfs = false); + const bool force_sysfs = false) override; - bool readTemperatureThreshold(std::string_view sensor_name, TemperatureThreshold *out) const; + bool readTemperatureThreshold(std::string_view sensor_name, + TemperatureThreshold *out) const override; // Read the value of a single cooling device. - bool readCoolingDevice(std::string_view cooling_device, CoolingDevice *out) const; + bool readCoolingDevice(std::string_view cooling_device, CoolingDevice *out) const override; // Get SensorInfo Map - const std::unordered_map<std::string, SensorInfo> &GetSensorInfoMap() const { + const std::unordered_map<std::string, SensorInfo> &GetSensorInfoMap() const override { return sensor_info_map_; } // Get CdevInfo Map - const std::unordered_map<std::string, CdevInfo> &GetCdevInfoMap() const { + const std::unordered_map<std::string, CdevInfo> &GetCdevInfoMap() const override { return cooling_device_info_map_; } // Get SensorStatus Map - const std::unordered_map<std::string, SensorStatus> &GetSensorStatusMap() const { + const std::unordered_map<std::string, SensorStatus> &GetSensorStatusMap() const override { std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_); return sensor_status_map_; } // Get ThermalThrottling Map const std::unordered_map<std::string, ThermalThrottlingStatus> &GetThermalThrottlingStatusMap() - const { + const override { return thermal_throttling_.GetThermalThrottlingStatusMap(); } // Get PowerRailInfo Map - const std::unordered_map<std::string, PowerRailInfo> &GetPowerRailInfoMap() const { + const std::unordered_map<std::string, PowerRailInfo> &GetPowerRailInfoMap() const override { return power_files_.GetPowerRailInfoMap(); } // Get PowerStatus Map - const std::unordered_map<std::string, PowerStatus> &GetPowerStatusMap() const { + const std::unordered_map<std::string, PowerStatus> &GetPowerStatusMap() const override { return power_files_.GetPowerStatusMap(); } // Get Thermal Stats Sensor Map - const std::unordered_map<std::string, SensorTempStats> GetSensorTempStatsSnapshot() { + const std::unordered_map<std::string, SensorTempStats> GetSensorTempStatsSnapshot() override { return thermal_stats_helper_.GetSensorTempStatsSnapshot(); } // Get Thermal Stats Sensor, Binded Cdev State Request Map const std::unordered_map<std::string, std::unordered_map<std::string, ThermalStats<int>>> - GetSensorCoolingDeviceRequestStatsSnapshot() { + GetSensorCoolingDeviceRequestStatsSnapshot() override { return thermal_stats_helper_.GetSensorCoolingDeviceRequestStatsSnapshot(); } - void sendPowerExtHint(const Temperature &t); - bool isAidlPowerHalExist() { return power_hal_service_.isAidlPowerHalExist(); } - bool isPowerHalConnected() { return power_hal_service_.isPowerHalConnected(); } - bool isPowerHalExtConnected() { return power_hal_service_.isPowerHalExtConnected(); } + bool isAidlPowerHalExist() override { return power_hal_service_.isAidlPowerHalExist(); } + bool isPowerHalConnected() override { return power_hal_service_.isPowerHalConnected(); } + bool isPowerHalExtConnected() override { return power_hal_service_.isPowerHalExtConnected(); } private: bool initializeSensorMap(const std::unordered_map<std::string, std::string> &path_map); @@ -169,9 +203,10 @@ class ThermalHelper { // Read temperature data according to thermal sensor's info bool readThermalSensor(std::string_view sensor_name, float *temp, const bool force_sysfs, std::map<std::string, float> *sensor_log_map); - bool connectToPowerHal(); - void updateSupportedPowerHints(); void updateCoolingDevices(const std::vector<std::string> &cooling_devices_to_update); + // Check the max CDEV state for cdev_ceiling + void maxCoolingRequestCheck( + std::unordered_map<std::string, BindedCdevInfo> *binded_cdev_info_map); sp<ThermalWatcher> thermal_watcher_; PowerFiles power_files_; ThermalFiles thermal_sensors_; diff --git a/thermal/utils/power_files.cpp b/thermal/utils/power_files.cpp index 50cc5b62..767f434b 100644 --- a/thermal/utils/power_files.cpp +++ b/thermal/utils/power_files.cpp @@ -39,6 +39,28 @@ constexpr std::string_view kEnergyValueNode("energy_value"); using ::android::base::ReadFileToString; using ::android::base::StringPrintf; +namespace { +bool calculateAvgPower(std::string_view power_rail, const PowerSample &last_sample, + const PowerSample &curr_sample, float *avg_power) { + *avg_power = NAN; + const auto duration = curr_sample.duration - last_sample.duration; + const auto deltaEnergy = curr_sample.energy_counter - last_sample.energy_counter; + if (!last_sample.duration) { + LOG(VERBOSE) << "Power rail " << power_rail.data() + << ": all power samples have not been collected yet"; + } else if (duration <= 0 || deltaEnergy < 0) { + LOG(ERROR) << "Power rail " << power_rail.data() << " is invalid: duration = " << duration + << ", deltaEnergy = " << deltaEnergy; + return false; + } else { + *avg_power = static_cast<float>(deltaEnergy) / static_cast<float>(duration); + LOG(VERBOSE) << "Power rail " << power_rail.data() << ", avg power = " << *avg_power + << ", duration = " << duration << ", deltaEnergy = " << deltaEnergy; + } + return true; +} +} // namespace + bool PowerFiles::registerPowerRailsToWatch(const Json::Value &config) { if (!ParsePowerRailInfo(config, &power_rail_info_map_)) { LOG(ERROR) << "Failed to parse power rail info config"; @@ -113,6 +135,9 @@ bool PowerFiles::registerPowerRailsToWatch(const Json::Value &config) { } LOG(INFO) << "Successfully to register power rail " << power_rail_info_pair.first; } + + power_status_log_ = {.prev_log_time = boot_clock::now(), + .prev_energy_info_map = energy_info_map_}; return true; } @@ -212,33 +237,16 @@ bool PowerFiles::updateEnergyValues(void) { float PowerFiles::updateAveragePower(std::string_view power_rail, std::queue<PowerSample> *power_history) { float avg_power = NAN; - if (!energy_info_map_.count(power_rail.data())) { LOG(ERROR) << " Could not find power rail " << power_rail.data(); return avg_power; } const auto last_sample = power_history->front(); const auto curr_sample = energy_info_map_.at(power_rail.data()); - const auto duration = curr_sample.duration - last_sample.duration; - const auto deltaEnergy = curr_sample.energy_counter - last_sample.energy_counter; - - if (!last_sample.duration) { - LOG(VERBOSE) << "Power rail " << power_rail.data() - << ": all power samples have not been collected yet"; - } else if (duration <= 0 || deltaEnergy < 0) { - LOG(ERROR) << "Power rail " << power_rail.data() << " is invalid: duration = " << duration - << ", deltaEnergy = " << deltaEnergy; - - return avg_power; - } else { - avg_power = static_cast<float>(deltaEnergy) / static_cast<float>(duration); - LOG(VERBOSE) << "Power rail " << power_rail.data() << ", avg power = " << avg_power - << ", duration = " << duration << ", deltaEnergy = " << deltaEnergy; + if (calculateAvgPower(power_rail, last_sample, curr_sample, &avg_power)) { + power_history->pop(); + power_history->push(curr_sample); } - - power_history->pop(); - power_history->push(curr_sample); - return avg_power; } @@ -335,6 +343,43 @@ bool PowerFiles::refreshPowerStatus(void) { return true; } +void PowerFiles::logPowerStatus(const boot_clock::time_point &now) { + // calculate energy and print + uint8_t power_rail_log_cnt = 0; + uint64_t max_duration = 0; + float tot_power = 0.0; + std::string out; + for (const auto &energy_info_pair : energy_info_map_) { + const auto &rail = energy_info_pair.first; + if (!power_status_log_.prev_energy_info_map.count(rail)) { + continue; + } + const auto &last_sample = power_status_log_.prev_energy_info_map.at(rail); + const auto &curr_sample = energy_info_pair.second; + float avg_power = NAN; + if (calculateAvgPower(rail, last_sample, curr_sample, &avg_power) && avg_power != NAN) { + // start of new line + if (power_rail_log_cnt % kMaxPowerLogPerLine == 0) { + if (power_rail_log_cnt != 0) { + out.append("\n"); + } + out.append("Power rails "); + } + out.append(StringPrintf("[%s: %0.2f mW] ", rail.c_str(), avg_power)); + power_rail_log_cnt++; + tot_power += avg_power; + max_duration = std::max(max_duration, curr_sample.duration - last_sample.duration); + } + } + + if (power_rail_log_cnt) { + LOG(INFO) << StringPrintf("Power rails total power: %0.2f mW for %" PRId64 " ms", tot_power, + max_duration); + LOG(INFO) << out; + } + power_status_log_ = {.prev_log_time = now, .prev_energy_info_map = energy_info_map_}; +} + } // namespace implementation } // namespace thermal } // namespace hardware diff --git a/thermal/utils/power_files.h b/thermal/utils/power_files.h index bcf8e820..0b00604f 100644 --- a/thermal/utils/power_files.h +++ b/thermal/utils/power_files.h @@ -47,6 +47,12 @@ struct PowerStatus { float last_updated_avg_power; }; +struct PowerStatusLog { + boot_clock::time_point prev_log_time; + // energy sample at last logging + std::unordered_map<std::string, PowerSample> prev_energy_info_map; +}; + // A helper class for monitoring power rails. class PowerFiles { public: @@ -58,6 +64,12 @@ class PowerFiles { bool registerPowerRailsToWatch(const Json::Value &config); // Update the power data from ODPM sysfs bool refreshPowerStatus(void); + // Log the power data for the duration + void logPowerStatus(const boot_clock::time_point &now); + // Get previous power log time_point + const boot_clock::time_point &GetPrevPowerLogTime() const { + return power_status_log_.prev_log_time; + } // Get power status map const std::unordered_map<std::string, PowerStatus> &GetPowerStatusMap() const { std::shared_lock<std::shared_mutex> _lock(power_status_map_mutex_); @@ -86,6 +98,7 @@ class PowerFiles { std::unordered_map<std::string, PowerRailInfo> power_rail_info_map_; // The set to store the energy source paths std::unordered_set<std::string> energy_path_set_; + PowerStatusLog power_status_log_; }; } // namespace implementation diff --git a/thermal/utils/powerhal_helper.cpp b/thermal/utils/powerhal_helper.cpp index c40d2629..f8ac7d0b 100644 --- a/thermal/utils/powerhal_helper.cpp +++ b/thermal/utils/powerhal_helper.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define ATRACE_TAG (ATRACE_TAG_THERMAL | ATRACE_TAG_HAL) + #include "powerhal_helper.h" #include <android-base/file.h> @@ -29,7 +31,6 @@ #include <thread> #include <vector> -#include "thermal_info.h" #include "thermal_throttling.h" namespace aidl { @@ -87,9 +88,103 @@ bool PowerHalService::connect() { power_hal_aidl_exist_ = false; } + if (power_hal_ext_aidl_death_recipient_.get() == nullptr) { + power_hal_ext_aidl_death_recipient_ = ndk::ScopedAIBinder_DeathRecipient( + AIBinder_DeathRecipient_new(onPowerHalExtAidlBinderDied)); + } + + auto linked = AIBinder_linkToDeath(power_hal_ext_aidl_->asBinder().get(), + power_hal_ext_aidl_death_recipient_.get(), this); + + if (linked != STATUS_OK) { + LOG(ERROR) << "Failed to register power_hal_ext death recipient"; + } + return true; } +void PowerHalService::reconnect() { + ATRACE_CALL(); + if (!connect()) { + LOG(ERROR) << " Failed to reconnect power_hal_ext"; + return; + } + + LOG(INFO) << "Resend the power hints when power_hal_ext is reconnected"; + std::lock_guard<std::shared_mutex> _lock(powerhint_status_mutex_); + for (const auto &[sensor_name, supported_powerhint] : supported_powerhint_map_) { + std::stringstream log_buf; + for (const auto &severity : ::ndk::enum_range<ThrottlingSeverity>()) { + bool mode = severity <= supported_powerhint.prev_hint_severity; + setMode(sensor_name, severity, mode); + log_buf << toString(severity).c_str() << ":" << mode << " "; + } + + LOG(INFO) << sensor_name << " send powerhint: " << log_buf.str(); + log_buf.clear(); + } + return; +} + +void PowerHalService::updateSupportedPowerHints( + const std::unordered_map<std::string, SensorInfo> &sensor_info_map_) { + for (auto const &name_status_pair : sensor_info_map_) { + if (!(name_status_pair.second.send_powerhint)) { + continue; + } + ThrottlingSeverity current_severity = ThrottlingSeverity::NONE; + for (const auto &severity : ::ndk::enum_range<ThrottlingSeverity>()) { + if (severity == ThrottlingSeverity::NONE) { + supported_powerhint_map_[name_status_pair.first] + .hint_severity_map[ThrottlingSeverity::NONE] = ThrottlingSeverity::NONE; + continue; + } + + bool isSupported = false; + ndk::ScopedAStatus isSupportedResult; + + if (power_hal_ext_aidl_ != nullptr) { + isSupported = isModeSupported(name_status_pair.first, severity); + } + if (isSupported) + current_severity = severity; + supported_powerhint_map_[name_status_pair.first].hint_severity_map[severity] = + current_severity; + } + } +} + +void PowerHalService::sendPowerExtHint(const Temperature &t) { + ATRACE_CALL(); + std::lock_guard<std::shared_mutex> _lock(powerhint_status_mutex_); + ThrottlingSeverity prev_hint_severity = supported_powerhint_map_[t.name].prev_hint_severity; + ThrottlingSeverity current_hint_severity = + supported_powerhint_map_[t.name].hint_severity_map[t.throttlingStatus]; + std::stringstream log_buf; + + if (!power_hal_aidl_exist_) { + LOG(ERROR) << "power_hal_aidl is not exist"; + return; + } + + if (prev_hint_severity == current_hint_severity) { + return; + } + + for (const auto &severity : ::ndk::enum_range<ThrottlingSeverity>()) { + if (severity != supported_powerhint_map_[t.name].hint_severity_map[severity]) { + continue; + } + bool mode = severity <= current_hint_severity; + setMode(t.name, severity, mode); + log_buf << toString(severity).c_str() << ":" << mode << " "; + } + + LOG(INFO) << t.name << " send powerhint: " << log_buf.str(); + + supported_powerhint_map_[t.name].prev_hint_severity = current_hint_severity; +} + bool PowerHalService::isModeSupported(const std::string &type, const ThrottlingSeverity &t) { bool isSupported = false; if (!connect()) { @@ -115,8 +210,6 @@ void PowerHalService::setMode(const std::string &type, const ThrottlingSeverity } std::string power_hint = StringPrintf("THERMAL_%s_%s", type.c_str(), toString(t).c_str()); - LOG(INFO) << (error_on_exit ? "Resend Hint " : "Send Hint ") << power_hint - << " Enable: " << std::boolalpha << enable; lock_.lock(); if (!power_hal_ext_aidl_->setMode(power_hint, enable).isOk()) { LOG(ERROR) << "Fail to set mode, Hint: " << power_hint; diff --git a/thermal/utils/powerhal_helper.h b/thermal/utils/powerhal_helper.h index 0769aa23..ac3d8b5e 100644 --- a/thermal/utils/powerhal_helper.h +++ b/thermal/utils/powerhal_helper.h @@ -17,8 +17,10 @@ #pragma once #include <aidl/android/hardware/power/IPower.h> +#include <aidl/android/hardware/thermal/IThermal.h> #include <aidl/android/hardware/thermal/ThrottlingSeverity.h> #include <aidl/google/hardware/power/extension/pixel/IPowerExt.h> +#include <utils/Trace.h> #include <queue> #include <shared_mutex> @@ -26,6 +28,8 @@ #include <unordered_map> #include <unordered_set> +#include "thermal_info.h" + namespace aidl { namespace android { namespace hardware { @@ -37,23 +41,47 @@ using ::aidl::google::hardware::power::extension::pixel::IPowerExt; using CdevRequestStatus = std::unordered_map<std::string, int>; +struct PowerHintstatus { + std::unordered_map<ThrottlingSeverity, ThrottlingSeverity> hint_severity_map; + ThrottlingSeverity prev_hint_severity; +}; + class PowerHalService { public: PowerHalService(); ~PowerHalService() = default; bool connect(); + void reconnect(); bool isAidlPowerHalExist() { return power_hal_aidl_exist_; } bool isModeSupported(const std::string &type, const ThrottlingSeverity &t); bool isPowerHalConnected() { return power_hal_aidl_ != nullptr; } bool isPowerHalExtConnected() { return power_hal_ext_aidl_ != nullptr; } void setMode(const std::string &type, const ThrottlingSeverity &t, const bool &enable, const bool error_on_exit = false); + void updateSupportedPowerHints( + const std::unordered_map<std::string, SensorInfo> &sensor_info_map_); + void sendPowerExtHint(const Temperature &t); private: + ndk::ScopedAIBinder_DeathRecipient power_hal_ext_aidl_death_recipient_; + static void onPowerHalExtAidlBinderDied(void *cookie) { + if (cookie) { + auto *e = static_cast<PowerHalService *>(cookie); + { + std::lock_guard<std::mutex> lock(e->lock_); + e->power_hal_aidl_ = nullptr; + e->power_hal_ext_aidl_ = nullptr; + } + e->reconnect(); + } + } + bool power_hal_aidl_exist_; std::shared_ptr<IPower> power_hal_aidl_; std::shared_ptr<IPowerExt> power_hal_ext_aidl_; std::mutex lock_; + std::unordered_map<std::string, PowerHintstatus> supported_powerhint_map_; + mutable std::shared_mutex powerhint_status_mutex_; }; } // namespace implementation diff --git a/thermal/utils/thermal_files.cpp b/thermal/utils/thermal_files.cpp index 26aaf450..c42fa1c3 100644 --- a/thermal/utils/thermal_files.cpp +++ b/thermal/utils/thermal_files.cpp @@ -63,6 +63,11 @@ bool ThermalFiles::readThermalFile(std::string_view thermal_name, std::string *d return false; } + if (sensor_reading.size() <= 1) { + LOG(ERROR) << thermal_name << "'s return size:" << sensor_reading.size() << " is invalid"; + return false; + } + // Strip the newline. *data = ::android::base::Trim(sensor_reading); return true; diff --git a/thermal/utils/thermal_info.cpp b/thermal/utils/thermal_info.cpp index c00bf63e..c5535c5f 100644 --- a/thermal/utils/thermal_info.cpp +++ b/thermal/utils/thermal_info.cpp @@ -162,7 +162,8 @@ bool ParseVirtualSensorInfo(const std::string_view name, const Json::Value &sens std::vector<std::string> linked_sensors; std::vector<SensorFusionType> linked_sensors_type; std::vector<std::string> trigger_sensors; - std::vector<float> coefficients; + std::vector<std::string> coefficients; + std::vector<SensorFusionType> coefficients_type; FormulaOption formula = FormulaOption::COUNT_THRESHOLD; Json::Value values = sensor["Combination"]; @@ -192,6 +193,8 @@ bool ParseVirtualSensorInfo(const std::string_view name, const Json::Value &sens linked_sensors_type.emplace_back(SensorFusionType::SENSOR); } else if (values[j].asString().compare("ODPM") == 0) { linked_sensors_type.emplace_back(SensorFusionType::ODPM); + } else if (values[j].asString().compare("CONSTANT") == 0) { + linked_sensors_type.emplace_back(SensorFusionType::CONSTANT); } else { LOG(ERROR) << "Sensor[" << name << "] has invalid CombinationType settings " << values[j].asString(); @@ -206,7 +209,7 @@ bool ParseVirtualSensorInfo(const std::string_view name, const Json::Value &sens if (values.size()) { coefficients.reserve(values.size()); for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) { - coefficients.emplace_back(getFloatFromValue(values[j])); + coefficients.emplace_back(values[j].asString()); LOG(INFO) << "Sensor[" << name << "]'s coefficient[" << j << "]: " << coefficients[j]; } } else { @@ -217,6 +220,40 @@ bool ParseVirtualSensorInfo(const std::string_view name, const Json::Value &sens LOG(ERROR) << "Sensor[" << name << "] has invalid Coefficient size"; return false; } + + values = sensor["CoefficientType"]; + if (!values.size()) { + coefficients_type.reserve(linked_sensors.size()); + for (size_t j = 0; j < linked_sensors.size(); ++j) { + coefficients_type.emplace_back(SensorFusionType::CONSTANT); + } + } else if (values.size() != coefficients.size()) { + LOG(ERROR) << "Sensor[" << name << "] has invalid coefficient type size"; + return false; + } else { + for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) { + if (values[j].asString().compare("CONSTANT") == 0) { + coefficients_type.emplace_back(SensorFusionType::CONSTANT); + } else if (values[j].asString().compare("SENSOR") == 0) { + coefficients_type.emplace_back(SensorFusionType::SENSOR); + } else if (values[j].asString().compare("ODPM") == 0) { + coefficients_type.emplace_back(SensorFusionType::ODPM); + } else { + LOG(ERROR) << "Sensor[" << name << "] has invalid coefficient options " + << values[j].asString(); + return false; + } + LOG(INFO) << "Sensor[" << name << "]'s coefficient type[" << j + << "]: " << coefficients_type[j]; + } + } + + if (linked_sensors.size() != coefficients_type.size()) { + LOG(ERROR) << "Sensor[" << name + << "]'s combination size is not matched with coefficient type size"; + return false; + } + if (!sensor["Offset"].empty()) { offset = sensor["Offset"].asFloat(); } @@ -255,8 +292,9 @@ bool ParseVirtualSensorInfo(const std::string_view name, const Json::Value &sens LOG(ERROR) << "Sensor[" << name << "]'s Formula is invalid"; return false; } - virtual_sensor_info->reset(new VirtualSensorInfo{ - linked_sensors, linked_sensors_type, coefficients, offset, trigger_sensors, formula}); + virtual_sensor_info->reset(new VirtualSensorInfo{linked_sensors, linked_sensors_type, + coefficients, coefficients_type, offset, + trigger_sensors, formula}); return true; } @@ -332,6 +370,7 @@ bool ParseBindedCdevInfo(const Json::Value &values, std::string power_rail; bool high_power_check = false; bool throttling_with_power_link = false; + bool enabled = true; CdevArray cdev_floor_with_power_link; cdev_floor_with_power_link.fill(0); @@ -387,6 +426,9 @@ bool ParseBindedCdevInfo(const Json::Value &values, } } } + if (values[j]["Disabled"].asBool()) { + enabled = false; + } (*binded_cdev_info_map)[cdev_name] = { .limit_info = limit_info, @@ -400,6 +442,7 @@ bool ParseBindedCdevInfo(const Json::Value &values, .max_throttle_step = max_throttle_step, .cdev_floor_with_power_link = cdev_floor_with_power_link, .power_rail = power_rail, + .enabled = enabled, }; } return true; @@ -531,9 +574,48 @@ bool ParseSensorThrottlingInfo(const std::string_view name, const Json::Value &s LOG(ERROR) << "Sensor[" << name << "]: failed to parse BindedCdevInfo"; return false; } + Json::Value values; + ProfileMap profile_map; + + values = sensor["Profile"]; + for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) { + Json::Value sub_values; + const std::string &mode = values[j]["Mode"].asString(); + std::unordered_map<std::string, BindedCdevInfo> binded_cdev_info_map_profile; + if (!ParseBindedCdevInfo(values[j]["BindedCdevInfo"], &binded_cdev_info_map_profile, + support_pid, &support_hard_limit)) { + LOG(ERROR) << "Sensor[" << name << " failed to parse BindedCdevInfo profile"; + } + // Check if the binded_cdev_info_map_profile is valid + if (binded_cdev_info_map.size() != binded_cdev_info_map_profile.size()) { + LOG(ERROR) << "Sensor[" << name << "]:'s profile map size should not be changed"; + return false; + } else { + for (const auto &binded_cdev_info_pair : binded_cdev_info_map_profile) { + if (binded_cdev_info_map.count(binded_cdev_info_pair.first)) { + if (binded_cdev_info_pair.second.power_rail != + binded_cdev_info_map.at(binded_cdev_info_pair.first).power_rail) { + LOG(ERROR) << "Sensor[" << name << "]:'s profile " << mode << " binded " + << binded_cdev_info_pair.first + << "'s power rail is not included in default rules"; + return false; + } else { + LOG(INFO) << "Sensor[" << name << "]:'s profile " << mode + << " is parsed successfully"; + } + } else { + LOG(ERROR) << "Sensor[" << name << "]'s profile " << mode << " binded " + << binded_cdev_info_pair.first + << " is not included in default rules"; + return false; + } + } + } + profile_map[mode] = binded_cdev_info_map_profile; + } std::unordered_map<std::string, ThrottlingArray> excluded_power_info_map; - Json::Value values = sensor["ExcludedPowerInfo"]; + values = sensor["ExcludedPowerInfo"]; for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) { Json::Value sub_values; const std::string &power_rail = values[j]["PowerRail"].asString(); @@ -555,7 +637,7 @@ bool ParseSensorThrottlingInfo(const std::string_view name, const Json::Value &s } throttling_info->reset(new ThrottlingInfo{ k_po, k_pu, k_i, k_d, i_max, max_alloc_power, min_alloc_power, s_power, i_cutoff, - i_default, tran_cycle, excluded_power_info_map, binded_cdev_info_map}); + i_default, tran_cycle, excluded_power_info_map, binded_cdev_info_map, profile_map}); *support_throttling = support_pid | support_hard_limit; return true; } @@ -797,6 +879,16 @@ bool ParseSensorInfo(const Json::Value &config, } LOG(INFO) << "Sensor[" << name << "]'s Time resolution: " << time_resolution.count(); + float step_ratio = NAN; + if (!sensors[i]["StepRatio"].empty()) { + step_ratio = sensors[i]["StepRatio"].asFloat(); + if (step_ratio < 0 || step_ratio > 1) { + LOG(ERROR) << "Sensor[" << name << "]'s StepRatio should be set 0 ~ 1"; + sensors_parsed->clear(); + return false; + } + } + if (is_hidden && send_cb) { LOG(ERROR) << "is_hidden and send_cb cannot be enabled together"; sensors_parsed->clear(); @@ -833,6 +925,7 @@ bool ParseSensorInfo(const Json::Value &config, .polling_delay = polling_delay, .passive_delay = passive_delay, .time_resolution = time_resolution, + .step_ratio = step_ratio, .send_cb = send_cb, .send_powerhint = send_powerhint, .is_watch = is_watch, @@ -939,7 +1032,7 @@ bool ParsePowerRailInfo(const Json::Value &config, LOG(INFO) << "PowerRail[" << i << "]'s Rail: " << rail; std::vector<std::string> linked_power_rails; - std::vector<float> coefficients; + std::vector<float> coefficient; float offset = 0; FormulaOption formula = FormulaOption::COUNT_THRESHOLD; bool is_virtual_power_rail = false; @@ -969,11 +1062,11 @@ bool ParsePowerRailInfo(const Json::Value &config, values = power_rails[i]["Coefficient"]; if (values.size()) { - coefficients.reserve(values.size()); + coefficient.reserve(values.size()); for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) { - coefficients.emplace_back(getFloatFromValue(values[j])); + coefficient.emplace_back(getFloatFromValue(values[j])); LOG(INFO) << "PowerRail[" << name << "]'s coefficient[" << j - << "]: " << coefficients[j]; + << "]: " << coefficient[j]; } } else { LOG(ERROR) << "PowerRails[" << name << "] has no coefficient for VirtualRail"; @@ -981,7 +1074,7 @@ bool ParsePowerRailInfo(const Json::Value &config, return false; } - if (linked_power_rails.size() != coefficients.size()) { + if (linked_power_rails.size() != coefficient.size()) { LOG(ERROR) << "PowerRails[" << name << "]'s combination size is not matched with coefficient size"; power_rails_parsed->clear(); @@ -992,7 +1085,7 @@ bool ParsePowerRailInfo(const Json::Value &config, offset = power_rails[i]["Offset"].asFloat(); } - if (linked_power_rails.size() != coefficients.size()) { + if (linked_power_rails.size() != coefficient.size()) { LOG(ERROR) << "PowerRails[" << name << "]'s combination size is not matched with coefficient size"; power_rails_parsed->clear(); @@ -1017,7 +1110,7 @@ bool ParsePowerRailInfo(const Json::Value &config, std::unique_ptr<VirtualPowerRailInfo> virtual_power_rail_info; if (is_virtual_power_rail) { virtual_power_rail_info.reset( - new VirtualPowerRailInfo{linked_power_rails, coefficients, offset, formula}); + new VirtualPowerRailInfo{linked_power_rails, coefficient, offset, formula}); } power_sample_count = power_rails[i]["PowerSampleCount"].asInt(); diff --git a/thermal/utils/thermal_info.h b/thermal/utils/thermal_info.h index 5b2e8b80..12997f26 100644 --- a/thermal/utils/thermal_info.h +++ b/thermal/utils/thermal_info.h @@ -40,6 +40,9 @@ using ThrottlingArray = std::array<float, static_cast<size_t>(kThrottlingSeverit using CdevArray = std::array<int, static_cast<size_t>(kThrottlingSeverityCount)>; constexpr std::chrono::milliseconds kMinPollIntervalMs = std::chrono::milliseconds(2000); constexpr std::chrono::milliseconds kUeventPollTimeoutMs = std::chrono::milliseconds(300000); +// TODO(b/292044404): Add debug config to make them easily configurable +constexpr std::chrono::milliseconds kPowerLogIntervalMs = std::chrono::milliseconds(60000); +constexpr int kMaxPowerLogPerLine = 6; // Max number of time_in_state buckets is 20 in atoms // VendorSensorCoolingDeviceStats, VendorTempResidencyStats constexpr int kMaxStatsResidencyCount = 20; @@ -93,12 +96,15 @@ struct StatsConfig { enum SensorFusionType : uint32_t { SENSOR = 0, ODPM, + CONSTANT, }; struct VirtualSensorInfo { std::vector<std::string> linked_sensors; std::vector<SensorFusionType> linked_sensors_type; - std::vector<float> coefficients; + std::vector<std::string> coefficients; + std::vector<SensorFusionType> coefficients_type; + float offset; std::vector<std::string> trigger_sensors; FormulaOption formula; @@ -134,8 +140,12 @@ struct BindedCdevInfo { bool high_power_check; // The flag for only triggering throttling until all power samples are collected bool throttling_with_power_link; + bool enabled; }; +// The map to store the CDEV throttling info for each profile +using ProfileMap = std::unordered_map<std::string, std::unordered_map<std::string, BindedCdevInfo>>; + struct ThrottlingInfo { ThrottlingArray k_po; ThrottlingArray k_pu; @@ -150,6 +160,7 @@ struct ThrottlingInfo { int tran_cycle; std::unordered_map<std::string, ThrottlingArray> excluded_power_info_map; std::unordered_map<std::string, BindedCdevInfo> binded_cdev_info_map; + ProfileMap profile_map; }; struct SensorInfo { @@ -164,6 +175,9 @@ struct SensorInfo { std::chrono::milliseconds polling_delay; std::chrono::milliseconds passive_delay; std::chrono::milliseconds time_resolution; + // The StepRatio value which is used for smoothing transient w/ the equation: + // Temp = CurrentTemp * StepRatio + LastTemp * (1 - StepRatio) + float step_ratio; bool send_cb; bool send_powerhint; bool is_watch; diff --git a/thermal/utils/thermal_stats_helper.cpp b/thermal/utils/thermal_stats_helper.cpp index daaaf1c6..bbd99542 100644 --- a/thermal/utils/thermal_stats_helper.cpp +++ b/thermal/utils/thermal_stats_helper.cpp @@ -313,6 +313,9 @@ int ThermalStatsHelper::reportAllSensorTempStats(const std::shared_ptr<IStats> & count_failed_reporting++; } } + // Reset temp stats after reporting + temp_stats.max_temp = std::numeric_limits<float>::min(); + temp_stats.min_temp = std::numeric_limits<float>::max(); } return count_failed_reporting; } diff --git a/thermal/utils/thermal_throttling.cpp b/thermal/utils/thermal_throttling.cpp index 8aac95d4..57dca169 100644 --- a/thermal/utils/thermal_throttling.cpp +++ b/thermal/utils/thermal_throttling.cpp @@ -58,6 +58,28 @@ size_t getTargetStateOfPID(const SensorInfo &sensor_info, const ThrottlingSeveri return target_state; } +void ThermalThrottling::parseProfileProperty(std::string_view sensor_name, + const SensorInfo &sensor_info) { + if (sensor_info.throttling_info == nullptr) { + return; + } + + const std::string profile = ::android::base::GetProperty( + StringPrintf("vendor.thermal.%s.profile", sensor_name.data()), ""); + + if (profile.empty() || sensor_info.throttling_info->profile_map.count(profile)) { + if (profile != thermal_throttling_status_map_[sensor_name.data()].profile) { + LOG(INFO) << sensor_name.data() << ": throttling profile change to " + << ((profile.empty()) ? "default" : profile); + thermal_throttling_status_map_[sensor_name.data()].profile = profile; + } + } else { + LOG(ERROR) << sensor_name.data() << ": set profile to default because " << profile + << " is invalid"; + thermal_throttling_status_map_[sensor_name.data()].profile = ""; + } +} + void ThermalThrottling::clearThrottlingData(std::string_view sensor_name, const SensorInfo &sensor_info) { if (!thermal_throttling_status_map_.count(sensor_name.data())) { @@ -115,6 +137,7 @@ bool ThermalThrottling::registerThermalThrottling( static_cast<size_t>(ThrottlingSeverity::NONE); thermal_throttling_status_map_[sensor_name.data()].prev_power_budget = NAN; thermal_throttling_status_map_[sensor_name.data()].tran_cycle = 0; + thermal_throttling_status_map_[sensor_name.data()].profile = ""; for (auto &binded_cdev_pair : throttling_info->binded_cdev_info_map) { if (!cooling_device_info_map.count(binded_cdev_pair.first)) { @@ -247,10 +270,12 @@ float ThermalThrottling::updatePowerBudget(const Temperature &temp, const Sensor ATRACE_INT((sensor_name + std::string("-target_state")).c_str(), static_cast<int>(target_state)); - ATRACE_INT((sensor_name + std::string("-err")).c_str(), static_cast<int>(err / sensor_info.multiplier)); + ATRACE_INT((sensor_name + std::string("-err")).c_str(), + static_cast<int>(err / sensor_info.multiplier)); ATRACE_INT((sensor_name + std::string("-p")).c_str(), static_cast<int>(p)); ATRACE_INT((sensor_name + std::string("-d")).c_str(), static_cast<int>(d)); - ATRACE_INT((sensor_name + std::string("-temp")).c_str(), static_cast<int>(temp.value / sensor_info.multiplier)); + ATRACE_INT((sensor_name + std::string("-temp")).c_str(), + static_cast<int>(temp.value / sensor_info.multiplier)); throttling_status.prev_power_budget = power_budget; @@ -305,6 +330,7 @@ bool ThermalThrottling::allocatePowerToCdev( std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_); auto total_power_budget = updatePowerBudget(temp, sensor_info, time_elapsed_ms, curr_severity); + const auto &profile = thermal_throttling_status_map_[temp.name].profile; if (sensor_info.throttling_info->excluded_power_info_map.size()) { total_power_budget -= computeExcludedPower(sensor_info, curr_severity, power_status_map, @@ -317,10 +343,15 @@ bool ThermalThrottling::allocatePowerToCdev( } // Compute total cdev weight - for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) { + for (const auto &binded_cdev_info_pair : + (sensor_info.throttling_info->profile_map.count(profile) + ? sensor_info.throttling_info->profile_map.at(profile) + : sensor_info.throttling_info->binded_cdev_info_map)) { const auto cdev_weight = binded_cdev_info_pair.second .cdev_weight_for_pid[static_cast<size_t>(curr_severity)]; - if (std::isnan(cdev_weight) || cdev_weight == 0) { + if (!binded_cdev_info_pair.second.enabled) { + continue; + } else if (std::isnan(cdev_weight) || cdev_weight == 0) { allocated_cdev.insert(binded_cdev_info_pair.first); continue; } @@ -329,7 +360,9 @@ bool ThermalThrottling::allocatePowerToCdev( while (!is_budget_allocated) { for (const auto &binded_cdev_info_pair : - sensor_info.throttling_info->binded_cdev_info_map) { + (sensor_info.throttling_info->profile_map.count(profile) + ? sensor_info.throttling_info->profile_map.at(profile) + : sensor_info.throttling_info->binded_cdev_info_map)) { float cdev_power_adjustment = 0; const auto cdev_weight = binded_cdev_info_pair.second @@ -338,10 +371,6 @@ bool ThermalThrottling::allocatePowerToCdev( if (allocated_cdev.count(binded_cdev_info_pair.first)) { continue; } - if (std::isnan(cdev_weight) || !cdev_weight) { - allocated_cdev.insert(binded_cdev_info_pair.first); - continue; - } // Get the power data if (!power_data_invalid) { @@ -403,7 +432,9 @@ bool ThermalThrottling::allocatePowerToCdev( continue; } - if (!power_data_invalid && binded_cdev_info_pair.second.power_rail != "") { + if (!binded_cdev_info_pair.second.enabled) { + cdev_power_budget = cdev_info.state2power[0]; + } else if (!power_data_invalid && binded_cdev_info_pair.second.power_rail != "") { auto cdev_curr_power_budget = thermal_throttling_status_map_[temp.name].pid_power_budget_map.at( binded_cdev_info_pair.first); @@ -516,10 +547,22 @@ void ThermalThrottling::updateCdevRequestBySeverity(std::string_view sensor_name const SensorInfo &sensor_info, ThrottlingSeverity curr_severity) { std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_); - for (auto const &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) { + const auto &profile = thermal_throttling_status_map_[sensor_name.data()].profile; + + for (const auto &binded_cdev_info_pair : + (sensor_info.throttling_info->profile_map.count(profile) + ? sensor_info.throttling_info->profile_map.at(profile) + : sensor_info.throttling_info->binded_cdev_info_map)) { + if (!thermal_throttling_status_map_[sensor_name.data()].hardlimit_cdev_request_map.count( + binded_cdev_info_pair.first)) { + continue; + } thermal_throttling_status_map_[sensor_name.data()].hardlimit_cdev_request_map.at( binded_cdev_info_pair.first) = - binded_cdev_info_pair.second.limit_info[static_cast<size_t>(curr_severity)]; + (binded_cdev_info_pair.second.enabled) + ? binded_cdev_info_pair.second + .limit_info[static_cast<size_t>(curr_severity)] + : 0; LOG(VERBOSE) << "Hard Limit: Sensor " << sensor_name.data() << " update cdev " << binded_cdev_info_pair.first << " to " << thermal_throttling_status_map_[sensor_name.data()] @@ -633,6 +676,10 @@ void ThermalThrottling::thermalThrottlingUpdate( return; } + if (sensor_info.throttling_info->profile_map.size()) { + parseProfileProperty(temp.name.c_str(), sensor_info); + } + if (thermal_throttling_status_map_[temp.name].pid_power_budget_map.size()) { if (!allocatePowerToCdev(temp, sensor_info, curr_severity, time_elapsed_ms, power_status_map, cooling_device_info_map)) { @@ -670,12 +717,17 @@ void ThermalThrottling::computeCoolingDevicesRequest( auto &thermal_throttling_status = thermal_throttling_status_map_.at(sensor_name.data()); const auto &cdev_release_map = thermal_throttling_status.throttling_release_map; + const auto &profile = thermal_throttling_status_map_[sensor_name.data()].profile; + const auto &binded_cdev_info_map = + sensor_info.throttling_info->profile_map.count(profile) + ? sensor_info.throttling_info->profile_map.at(profile) + : sensor_info.throttling_info->binded_cdev_info_map; + for (auto &cdev_request_pair : thermal_throttling_status.cdev_status_map) { int pid_cdev_request = 0; int hardlimit_cdev_request = 0; const auto &cdev_name = cdev_request_pair.first; - const auto &binded_cdev_info = - sensor_info.throttling_info->binded_cdev_info_map.at(cdev_name); + const auto &binded_cdev_info = binded_cdev_info_map.at(cdev_name); const auto cdev_ceiling = binded_cdev_info.cdev_ceiling[static_cast<size_t>(curr_severity)]; const auto cdev_floor = binded_cdev_info.cdev_floor_with_power_link[static_cast<size_t>(curr_severity)]; diff --git a/thermal/utils/thermal_throttling.h b/thermal/utils/thermal_throttling.h index e83ee06a..76c41e0f 100644 --- a/thermal/utils/thermal_throttling.h +++ b/thermal/utils/thermal_throttling.h @@ -47,6 +47,7 @@ struct ThermalThrottlingStatus { float prev_power_budget; float budget_transient; int tran_cycle; + std::string profile; }; // Return the control temp target of PID algorithm @@ -61,6 +62,8 @@ class ThermalThrottling { ThermalThrottling(const ThermalThrottling &) = delete; void operator=(const ThermalThrottling &) = delete; + // Check if the thermal throttling profile need to be switched + void parseProfileProperty(std::string_view sensor_name, const SensorInfo &sensor_info); // Clear throttling data void clearThrottlingData(std::string_view sensor_name, const SensorInfo &sensor_info); // Register map for throttling algo diff --git a/vibrator/cs40l26/Hardware.h b/vibrator/cs40l26/Hardware.h index d5230fee..50e2cb66 100644 --- a/vibrator/cs40l26/Hardware.h +++ b/vibrator/cs40l26/Hardware.h @@ -144,11 +144,21 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { if (ioctl(fd, EVIOCGBIT(0, sizeof(val)), &val) > 0 && (val & (1 << EV_FF)) && ioctl(fd, EVIOCGNAME(sizeof(str)), &str) > 0 && strcmp(str, INPUT_EVENT_NAME.c_str()) == 0) { + // Get fd ready for input event ioctl(). mInputFd.reset(fd); // mInputFd.ok() becomes true. ALOGI("Control %s through %s", INPUT_EVENT_NAME.c_str(), g.gl_pathv[i]); - // Construct the sysfs device path. std::string path = g.gl_pathv[i]; + // Get fstream ready for input event write(). + saveName(path, &mInputIoStream); + mInputIoStream.open( + path, std::fstream::out | std::fstream::in | std::fstream::binary); + if (!mInputIoStream) { + ALOGE("Failed to open %s (%d): %s", path.c_str(), errno, + strerror(errno)); + } + + // Construct the sysfs device path. path = "/sys/class/input/" + path.substr(path.find("event"), std::string::npos) + "/../../../"; updatePathPrefix(path); @@ -185,9 +195,13 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { ALOGE("Invalid gain"); return false; } - if (write(mInputFd, (const void *)&gain, sizeof(gain)) != sizeof(gain)) { + mInputIoStream.write((const char *)&gain, sizeof(gain)); + mInputIoStream.flush(); + if (mInputIoStream.fail()) { + ALOGE("setFFGain fail"); return false; } + HWAPI_RECORD(StringPrintf("%d%%", value), &mInputIoStream); return true; } bool setFFEffect(struct ff_effect *effect, uint16_t timeoutMs) override { @@ -199,9 +213,10 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { if (((*effect).replay.length != timeoutMs) || (ioctl(mInputFd, EVIOCSFF, effect) < 0)) { ALOGE("setFFEffect fail"); return false; - } else { - return true; } + HWAPI_RECORD(StringPrintf("#%d: %dms", (*effect).id, (*effect).replay.length), + &mInputIoStream); + return true; } bool setFFPlay(int8_t index, bool value) override { ATRACE_NAME(StringPrintf("%s index:%d %s", __func__, index, value ? "on" : "off").c_str()); @@ -210,11 +225,14 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { .code = static_cast<uint16_t>(index), .value = value, }; - if (write(mInputFd, (const void *)&play, sizeof(play)) != sizeof(play)) { + mInputIoStream.write((const char *)&play, sizeof(play)); + mInputIoStream.flush(); + if (mInputIoStream.fail()) { + ALOGE("setFFPlay fail"); return false; - } else { - return true; } + HWAPI_RECORD(StringPrintf("#%d: %b", index, value), &mInputIoStream); + return true; } bool getHapticAlsaDevice(int *card, int *device) override { ATRACE_NAME(__func__); @@ -227,6 +245,7 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { std::string currentToken; std::getline(ss, currentToken, ':'); sscanf(currentToken.c_str(), "%d-%d", card, device); + saveName(StringPrintf("/dev/snd/pcmC%uD%up", *card, *device), &mPcmStream); return true; } } @@ -246,23 +265,27 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { ALOGE("cannot open pcm_out driver: %s", pcm_get_error(*haptic_pcm)); goto fail; } + HWAPI_RECORD(std::string("pcm_open"), &mPcmStream); ret = pcm_prepare(*haptic_pcm); if (ret < 0) { ALOGE("cannot prepare haptic_pcm: %s", pcm_get_error(*haptic_pcm)); goto fail; } + HWAPI_RECORD(std::string("pcm_prepare"), &mPcmStream); ret = pcm_start(*haptic_pcm); if (ret < 0) { ALOGE("cannot start haptic_pcm: %s", pcm_get_error(*haptic_pcm)); goto fail; } + HWAPI_RECORD(std::string("pcm_start"), &mPcmStream); return true; } else { if (*haptic_pcm) { pcm_close(*haptic_pcm); + HWAPI_RECORD(std::string("pcm_close"), &mPcmStream); *haptic_pcm = NULL; } return true; @@ -270,6 +293,7 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { fail: pcm_close(*haptic_pcm); + HWAPI_RECORD(std::string("pcm_close"), &mPcmStream); *haptic_pcm = NULL; return false; } @@ -308,6 +332,7 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { } *outEffectIndex = (*effect).id; *status = 0; + HWAPI_RECORD(StringPrintf("#%d: %dB", *outEffectIndex, numBytes), &mInputIoStream); return true; } bool eraseOwtEffect(int8_t effectIndex, std::vector<ff_effect> *effect) override { @@ -334,12 +359,14 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { break; } } + HWAPI_RECORD(StringPrintf("#%d", effectIndex), &mInputIoStream); } else { /* Flush all non-prestored effects of ff-core and driver. */ getEffectCount(&effectCountBefore); for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < FF_MAX_EFFECTS; i++) { if (ioctl(mInputFd, EVIOCRMFF, i) >= 0) { successFlush++; + HWAPI_RECORD(StringPrintf("#%d", i), &mInputIoStream); } } getEffectCount(&effectCountAfter); @@ -352,10 +379,57 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { } return true; } + bool isDbcSupported() override { + ATRACE_NAME(__func__); + return utils::getProperty("ro.vendor.vibrator.hal.dbc.enable", false); + } + + bool enableDbc() override { + ATRACE_NAME(__func__); + if (isDbcSupported()) { + open("dbc/dbc_env_rel_coef", &mDbcEnvRelCoef); + open("dbc/dbc_rise_headroom", &mDbcRiseHeadroom); + open("dbc/dbc_fall_headroom", &mDbcFallHeadroom); + open("dbc/dbc_tx_lvl_thresh_fs", &mDbcTxLvlThreshFs); + open("dbc/dbc_tx_lvl_hold_off_ms", &mDbcTxLvlHoldOffMs); + open("default/pm_active_timeout_ms", &mPmActiveTimeoutMs); + open("dbc/dbc_enable", &mDbcEnable); + + // Set values from config. Default if not found. + set(utils::getProperty("ro.vendor.vibrator.hal.dbc.envrelcoef", kDbcDefaultEnvRelCoef), + &mDbcEnvRelCoef); + set(utils::getProperty("ro.vendor.vibrator.hal.dbc.riseheadroom", + kDbcDefaultRiseHeadroom), + &mDbcRiseHeadroom); + set(utils::getProperty("ro.vendor.vibrator.hal.dbc.fallheadroom", + kDbcDefaultFallHeadroom), + &mDbcFallHeadroom); + set(utils::getProperty("ro.vendor.vibrator.hal.dbc.txlvlthreshfs", + kDbcDefaultTxLvlThreshFs), + &mDbcTxLvlThreshFs); + set(utils::getProperty("ro.vendor.vibrator.hal.dbc.txlvlholdoffms", + kDbcDefaultTxLvlHoldOffMs), + &mDbcTxLvlHoldOffMs); + set(utils::getProperty("ro.vendor.vibrator.hal.pm.activetimeout", + kDefaultPmActiveTimeoutMs), + &mPmActiveTimeoutMs); + set(kDbcEnable, &mDbcEnable); + return true; + } + return false; + } void debug(int fd) override { HwApiBase::debug(fd); } private: + static constexpr uint32_t kDbcDefaultEnvRelCoef = 8353728; + static constexpr uint32_t kDbcDefaultRiseHeadroom = 1909602; + static constexpr uint32_t kDbcDefaultFallHeadroom = 1909602; + static constexpr uint32_t kDbcDefaultTxLvlThreshFs = 2516583; + static constexpr uint32_t kDbcDefaultTxLvlHoldOffMs = 0; + static constexpr uint32_t kDefaultPmActiveTimeoutMs = 5; + static constexpr uint32_t kDbcEnable = 1; + std::ofstream mF0; std::ofstream mF0Offset; std::ofstream mRedc; @@ -366,7 +440,18 @@ class HwApi : public Vibrator::HwApi, private HwApiBase { std::ofstream mF0CompEnable; std::ofstream mRedcCompEnable; std::ofstream mMinOnOffInterval; + std::ofstream mInputIoStream; + std::ofstream mPcmStream; ::android::base::unique_fd mInputFd; + + // DBC Parameters + std::ofstream mDbcEnvRelCoef; + std::ofstream mDbcRiseHeadroom; + std::ofstream mDbcFallHeadroom; + std::ofstream mDbcTxLvlThreshFs; + std::ofstream mDbcTxLvlHoldOffMs; + std::ofstream mDbcEnable; + std::ofstream mPmActiveTimeoutMs; }; class HwCal : public Vibrator::HwCal, private HwCalBase { @@ -445,7 +530,7 @@ class HwCal : public Vibrator::HwCal, private HwCalBase { } bool isRedcCompEnabled() override { bool value; - getProperty("redc.comp.enabled", &value, true); + getProperty("redc.comp.enabled", &value, false); return value; } void debug(int fd) override { HwCalBase::debug(fd); } diff --git a/vibrator/cs40l26/Vibrator.cpp b/vibrator/cs40l26/Vibrator.cpp index ccc2fa68..8c303ffd 100644 --- a/vibrator/cs40l26/Vibrator.cpp +++ b/vibrator/cs40l26/Vibrator.cpp @@ -22,6 +22,7 @@ #include <log/log.h> #include <utils/Trace.h> +#include <chrono> #include <cinttypes> #include <cmath> #include <fstream> @@ -63,7 +64,7 @@ static constexpr int8_t MAX_PAUSE_TIMING_ERROR_MS = 1; // ALERT Irq Handling static constexpr uint32_t MAX_TIME_MS = UINT16_MAX; static constexpr auto ASYNC_COMPLETION_TIMEOUT = std::chrono::milliseconds(100); -static constexpr auto POLLING_TIMEOUT = 20; +static constexpr auto POLLING_TIMEOUT = 50; // POLLING_TIMEOUT < ASYNC_COMPLETION_TIMEOUT static constexpr int32_t COMPOSE_DELAY_MAX_MS = 10000; /* nsections is 8 bits. Need to preserve 1 section for the first delay before the first effect. */ @@ -518,14 +519,11 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal, createPwleMaxLevelLimitMap(); createBandwidthAmplitudeMap(); + // We need to do this until it's supported through WISCE + mHwApi->enableDbc(); + #ifdef ADAPTIVE_HAPTICS_V1 - mContextListener = CapoDetector::start(); - if (mContextListener == nullptr) { - ALOGE("%s, CapoDetector failed to start", __func__); - } else { - ALOGD("%s, CapoDetector started successfully! NanoAppID: 0x%x", __func__, - (uint32_t)mContextListener->getNanoppAppId()); - } + updateContext(); #endif /*ADAPTIVE_HAPTICS_V1*/ } @@ -558,6 +556,20 @@ ndk::ScopedAStatus Vibrator::off() { bool ret{true}; const std::scoped_lock<std::mutex> lock(mActiveId_mutex); + const auto startTime = std::chrono::system_clock::now(); + const auto endTime = startTime + std::chrono::milliseconds(POLLING_TIMEOUT); + auto now = startTime; + while (halState == ISSUED && now <= endTime) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + now = std::chrono::system_clock::now(); + } + if (halState == ISSUED && now > endTime) { + ALOGE("Timeout waiting for the actuator activation! (%d ms)", POLLING_TIMEOUT); + } else if (halState == PLAYING) { + ALOGD("Took %lld ms to wait for the actuator activation.", + std::chrono::duration_cast<std::chrono::milliseconds>(now - startTime).count()); + } + if (mActiveId >= 0) { /* Stop the active effect. */ if (!mHwApi->setFFPlay(mActiveId, false)) { @@ -565,6 +577,7 @@ ndk::ScopedAStatus Vibrator::off() { ALOGE("Failed to stop effect %d (%d): %s", mActiveId, errno, strerror(errno)); ret = false; } + halState = STOPPED; if ((mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) && (!mHwApi->eraseOwtEffect(mActiveId, &mFfEffects))) { @@ -581,6 +594,7 @@ ndk::ScopedAStatus Vibrator::off() { if (mF0Offset) { mHwApi->setF0Offset(0); } + halState = RESTORED; if (ret) { return ndk::ScopedAStatus::ok(); @@ -877,6 +891,7 @@ ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, const ALOGE("Failed to play effect %d (%d): %s", effectIndex, errno, strerror(errno)); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } + halState = ISSUED; mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback); return ndk::ScopedAStatus::ok(); @@ -894,7 +909,7 @@ uint16_t Vibrator::amplitudeToScale(float amplitude, float maximum, bool scalabl ratio = 100; #ifdef ADAPTIVE_HAPTICS_V1 - if (scalable && mContextEnable) { + if (scalable && mContextEnable && mContextListener) { uint32_t now = CapoDetector::getCurrentTimeInMs(); uint32_t last_played = mLastEffectPlayedTime; uint32_t lastFaceUpTime = 0; @@ -947,10 +962,24 @@ uint16_t Vibrator::amplitudeToScale(float amplitude, float maximum, bool scalabl void Vibrator::updateContext() { mContextEnable = mHwApi->getContextEnable(); - mFadeEnable = mHwApi->getContextFadeEnable(); - mScalingFactor = mHwApi->getContextScale(); - mScaleTime = mHwApi->getContextSettlingTime(); - mScaleCooldown = mHwApi->getContextCooldownTime(); + if (mContextEnable && !mContextEnabledPreviously) { + mContextListener = CapoDetector::start(); + if (mContextListener == nullptr) { + ALOGE("%s, CapoDetector failed to start", __func__); + } else { + mFadeEnable = mHwApi->getContextFadeEnable(); + mScalingFactor = mHwApi->getContextScale(); + mScaleTime = mHwApi->getContextSettlingTime(); + mScaleCooldown = mHwApi->getContextCooldownTime(); + ALOGD("%s, CapoDetector started successfully! NanoAppID: 0x%x, Scaling Factor: %d, " + "Scaling Time: %d, Cooldown Time: %d", + __func__, (uint32_t)mContextListener->getNanoppAppId(), mScalingFactor, + mScaleTime, mScaleCooldown); + + /* We no longer need to use this path */ + mContextEnabledPreviously = true; + } + } } ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum, bool scalable) { @@ -959,9 +988,7 @@ ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum, uint16_t scale; #ifdef ADAPTIVE_HAPTICS_V1 - if (scalable) { - updateContext(); - } + updateContext(); #endif /*ADAPTIVE_HAPTICS_V1*/ scale = amplitudeToScale(amplitude, maximum, scalable); @@ -1443,7 +1470,12 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { dprintf(fd, "AIDL:\n"); + dprintf(fd, " Global Gain: %0.2f\n", mLongEffectScale); + dprintf(fd, " Active Effect ID: %" PRId32 "\n", mActiveId); + dprintf(fd, " F0: %.02f\n", mResonantFrequency); dprintf(fd, " F0 Offset: %" PRIu32 "\n", mF0Offset); + dprintf(fd, " Redc: %.02f\n", mRedc); + dprintf(fd, " HAL State: %" PRIu32 "\n", halState); dprintf(fd, " Voltage Levels:\n"); dprintf(fd, " Tick Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mTickEffectVol[0], @@ -1453,15 +1485,15 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { dprintf(fd, " Long Effect Min: %" PRIu32 " Max: %" PRIu32 "\n", mLongEffectVol[0], mLongEffectVol[1]); - dprintf(fd, " FF effect:\n"); - dprintf(fd, " Physical waveform:\n"); + dprintf(fd, " FF Effect:\n"); + dprintf(fd, " Physical Waveform:\n"); dprintf(fd, "\tId\tIndex\tt ->\tt'\n"); for (uint8_t effectId = 0; effectId < WAVEFORM_MAX_PHYSICAL_INDEX; effectId++) { dprintf(fd, "\t%d\t%d\t%d\t%d\n", mFfEffects[effectId].id, mFfEffects[effectId].u.periodic.custom_data[1], mEffectDurations[effectId], mFfEffects[effectId].replay.length); } - dprintf(fd, " OWT waveform:\n"); + dprintf(fd, " OWT Waveform:\n"); dprintf(fd, "\tId\tBytes\tData\n"); for (uint8_t effectId = WAVEFORM_MAX_PHYSICAL_INDEX; effectId < WAVEFORM_MAX_INDEX; effectId++) { @@ -1479,6 +1511,65 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { } dprintf(fd, "\n"); + + dprintf(fd, "Versions:\n"); + std::ifstream verFile; + const auto verBinFileMode = std::ifstream::in | std::ifstream::binary; + std::string ver; + verFile.open("/sys/module/cs40l26_core/version"); + if (verFile.is_open()) { + getline(verFile, ver); + dprintf(fd, " Haptics Driver: %s\n", ver.c_str()); + verFile.close(); + } + verFile.open("/sys/module/cl_dsp_core/version"); + if (verFile.is_open()) { + getline(verFile, ver); + dprintf(fd, " DSP Driver: %s\n", ver.c_str()); + verFile.close(); + } + verFile.open("/vendor/firmware/cs40l26.wmfw", verBinFileMode); + if (verFile.is_open()) { + verFile.seekg(113); + dprintf(fd, " cs40l26.wmfw: %d.%d.%d\n", verFile.get(), verFile.get(), verFile.get()); + verFile.close(); + } + verFile.open("/vendor/firmware/cs40l26-calib.wmfw", verBinFileMode); + if (verFile.is_open()) { + verFile.seekg(113); + dprintf(fd, " cs40l26-calib.wmfw: %d.%d.%d\n", verFile.get(), verFile.get(), + verFile.get()); + verFile.close(); + } + verFile.open("/vendor/firmware/cs40l26.bin", verBinFileMode); + if (verFile.is_open()) { + while (getline(verFile, ver)) { + auto pos = ver.find("Date: "); + if (pos != std::string::npos) { + ver = ver.substr(pos + 6, pos + 15); + dprintf(fd, " cs40l26.bin: %s\n", ver.c_str()); + break; + } + } + verFile.close(); + } + verFile.open("/vendor/firmware/cs40l26-svc.bin", verBinFileMode); + if (verFile.is_open()) { + verFile.seekg(36); + getline(verFile, ver); + ver = ver.substr(ver.rfind('\\') + 1); + dprintf(fd, " cs40l26-svc.bin: %s\n", ver.c_str()); + verFile.close(); + } + verFile.open("/vendor/firmware/cs40l26-calib.bin", verBinFileMode); + if (verFile.is_open()) { + verFile.seekg(36); + getline(verFile, ver); + ver = ver.substr(ver.rfind('\\') + 1); + dprintf(fd, " cs40l26-calib.bin: %s\n", ver.c_str()); + verFile.close(); + } + dprintf(fd, "\n"); mHwApi->debug(fd); @@ -1487,14 +1578,23 @@ binder_status_t Vibrator::dump(int fd, const char **args, uint32_t numArgs) { mHwCal->debug(fd); - dprintf(fd, "Capo Info\n"); + dprintf(fd, "\n"); + + dprintf(fd, "Capo Info:\n"); + dprintf(fd, "Capo Enabled: %d\n", mContextEnable); if (mContextListener) { dprintf(fd, "Capo ID: 0x%x\n", (uint32_t)(mContextListener->getNanoppAppId())); dprintf(fd, "Capo State: %d\n", mContextListener->getCarriedPosition()); } + dprintf(fd, "\n"); + mStatsApi->debug(fd); + if (mHwApi->isDbcSupported()) { + dprintf(fd, "\nDBC Enabled\n"); + } + fsync(fd); return STATUS_OK; } @@ -1729,9 +1829,11 @@ void Vibrator::waitForComplete(std::shared_ptr<IVibratorCallback> &&callback) { if (!mHwApi->pollVibeState(VIBE_STATE_HAPTIC, POLLING_TIMEOUT)) { ALOGW("Failed to get state \"Haptic\""); } + halState = PLAYING; ATRACE_BEGIN("Vibrating"); mHwApi->pollVibeState(VIBE_STATE_STOPPED); ATRACE_END(); + halState = STOPPED; const std::scoped_lock<std::mutex> lock(mActiveId_mutex); uint32_t effectCount = WAVEFORM_MAX_PHYSICAL_INDEX; @@ -1751,6 +1853,7 @@ void Vibrator::waitForComplete(std::shared_ptr<IVibratorCallback> &&callback) { } mActiveId = -1; + halState = RESTORED; if (callback) { auto ret = callback->onComplete(); diff --git a/vibrator/cs40l26/Vibrator.h b/vibrator/cs40l26/Vibrator.h index 0c540682..c4a992ff 100644 --- a/vibrator/cs40l26/Vibrator.h +++ b/vibrator/cs40l26/Vibrator.h @@ -106,6 +106,11 @@ class Vibrator : public BnVibrator { int *status) = 0; // Erase OWT waveform virtual bool eraseOwtEffect(int8_t effectIndex, std::vector<ff_effect> *effect) = 0; + // Checks to see if DBC (Dynamic Boost Control) feature is supported + // by the target device. + virtual bool isDbcSupported() = 0; + // Configures and enables the DBC feature and all associated parameters + virtual bool enableDbc() = 0; // Emit diagnostic information to the given file. virtual void debug(int fd) = 0; }; @@ -266,9 +271,19 @@ class Vibrator : public BnVibrator { uint32_t mScalingFactor; uint32_t mScaleCooldown; bool mContextEnable; + bool mContextEnabledPreviously{false}; uint32_t mLastEffectPlayedTime = 0; float mLastPlayedScale = 0; sp<CapoDetector> mContextListener; + enum hal_state { + IDLE, + PREPARING, + ISSUED, + PLAYING, + STOPPED, + RESTORED, + }; + hal_state halState = IDLE; }; } // namespace vibrator diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual.rc b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual.rc index a2d4706b..6ea9d3b9 100644 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual.rc +++ b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual.rc @@ -18,6 +18,13 @@ service vendor.vibrator.cs40l26-dual /vendor/bin/hw/android.hardware.vibrator-se default/f0_comp_enable default/redc_comp_enable default/delay_before_stop_playback_us + dbc/dbc_env_rel_coef + dbc/dbc_rise_headroom + dbc/dbc_fall_headroom + dbc/dbc_tx_lvl_thresh_fs + dbc/dbc_tx_lvl_hold_off_ms + default/pm_active_timeout_ms + dbc/dbc_enable " setenv STATS_INSTANCE default diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26.rc b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26.rc index 8c9e2c2d..9a46abce 100644 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26.rc +++ b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26.rc @@ -18,6 +18,13 @@ service vendor.vibrator.cs40l26 /vendor/bin/hw/android.hardware.vibrator-service default/f0_comp_enable default/redc_comp_enable default/delay_before_stop_playback_us + dbc/dbc_env_rel_coef + dbc/dbc_rise_headroom + dbc/dbc_fall_headroom + dbc/dbc_tx_lvl_thresh_fs + dbc/dbc_tx_lvl_hold_off_ms + default/pm_active_timeout_ms + dbc/dbc_enable " setenv STATS_INSTANCE default diff --git a/vibrator/cs40l26/apex/Android.bp b/vibrator/cs40l26/apex/Android.bp deleted file mode 100644 index dea90ed6..00000000 --- a/vibrator/cs40l26/apex/Android.bp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2022 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. - -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -apex_key { - name: "com.google.pixel.vibrator.hal.key", - public_key: "com.google.pixel.vibrator.hal.avbpubkey", - private_key: "com.google.pixel.vibrator.hal.pem", -} - -android_app_certificate { - name: "com.google.pixel.vibrator.hal.certificate", - certificate: "com.google.pixel.vibrator.hal", -} - -genrule { - name: "gen-android.hardware.vibrator-service.cs40l26.rc", - srcs: [":android.hardware.vibrator-service.cs40l26.rc"], - out: ["android.hardware.vibrator-service.cs40l26.rc"], - cmd: "sed -E 's/\\/vendor\\/bin/\\/apex\\/com.google.pixel.vibrator.hal\\/bin/' $(in) > $(out)", -} - -prebuilt_etc { - name: "apex-android.hardware.vibrator-service.cs40l26.rc", - src: ":gen-android.hardware.vibrator-service.cs40l26.rc", - installable: false, -} - -apex { - name: "com.google.pixel.vibrator.hal", - manifest: "apex_manifest.json", - file_contexts: "file_contexts", // Default, please edit, see go/android-apex-howto - key: "com.google.pixel.vibrator.hal.key", - certificate: ":com.google.pixel.vibrator.hal.certificate", - vintf_fragments: [ - ":android.hardware.vibrator-service.cs40l26.xml", - ], - use_vndk_as_stable: true, - // Install the apex in /vendor/apex - soc_specific: true, - updatable: false, - binaries: [ - "android.hardware.vibrator-service.cs40l26", - ], - prebuilts: [ - "apex-android.hardware.vibrator-service.cs40l26.rc", - ], - overrides: ["android.hardware.vibrator-service.cs40l26"], -} diff --git a/vibrator/cs40l26/apex/apex_manifest.json b/vibrator/cs40l26/apex/apex_manifest.json deleted file mode 100644 index cbdc876c..00000000 --- a/vibrator/cs40l26/apex/apex_manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.google.pixel.vibrator.hal", - "version": 1 -} diff --git a/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.avbpubkey b/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.avbpubkey Binary files differdeleted file mode 100644 index 46b6769f..00000000 --- a/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.avbpubkey +++ /dev/null diff --git a/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.pem b/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.pem deleted file mode 100644 index 595322ac..00000000 --- a/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -vgJDLYQ0TdEWpv6trpA3s3hgFOx16g== ------END PRIVATE KEY----- diff --git a/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.pk8 b/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.pk8 Binary files differdeleted file mode 100644 index 8a5c5de2..00000000 --- a/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.pk8 +++ /dev/null diff --git a/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.x509.pem b/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.x509.pem deleted file mode 100644 index f1c4b481..00000000 --- a/vibrator/cs40l26/apex/com.google.pixel.vibrator.hal.x509.pem +++ /dev/null @@ -1,34 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIF3zCCA8cCFG61gvRZ1Gc1PG7iECvnY7zKSCaEMA0GCSqGSIb3DQEBCwUAMIGq -MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91 -bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi -MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEmMCQGA1UEAwwdY29t -Lmdvb2dsZS5waXhlbC52aWJyYXRvci5oYWwwIBcNMjIwODA1MTc1NTU4WhgPNDc2 -MDA3MDExNzU1NThaMIGqMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p -YTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4G -A1UECwwHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNv -bTEmMCQGA1UEAwwdY29tLmdvb2dsZS5waXhlbC52aWJyYXRvci5oYWwwggIiMA0G -CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCVoc9F0h6gf3M/Sm5K9rt8W1ZmB/Lu -fMlkMAZXqMWRbCYVPDg0hQkICLNEOEM76oFvMBCSS2HsZwdXgAguwy3IBhpuMC+t -mNkA9+6gAXXE3nBwQ/PjphS9vPPIQ+cvbEBiwaAFpAWCx9nb5VLBrkNBIFDuzE+t -He6sj8kD8vVWKqSEwHHwFdzvXLkSQvYKhrWFltcuUmkpxnHtfVJAH/iO7Vb/jR+s -H1YVqJcS35OjnjYzjDfQTr7aqV09K/3X9Srai5o0BiWRpcpytmK5MEIqEPJvewRz -e76Uw7kMO68f5OS6NV1iXqCI4l/k5v+Q0jlxecqJdWANWSegR5cli3eUS/zEDmZb -2OlrNACsr4hpGu5M2EuVwxg89SbKlUU2ughE6+c/56c45WRalyailaWltN5SF9zK -RaW1iGS3GDBXeVFqavydJLs9NDdEd0x9wAEdvN8rhrChkhjq18L9ls4d6JIC629V -n/GT63AHfulpklt5ueGOT1vQZdg6Z8LipcwAzIpTUZJEyVGbGp/o3jf80yYdfftU -AT51+i89xiJwKDBnCS0FDT54NFpp9yCKTZtLIGa+GweW4kVya2AG6iFdf0/GXPGz -khOPxhIyC8IfvK+Ozryn2X1ied44gHy6dKA8QXa5nRRxVPnOjJTzQp+vRty+dvzz -imdJENRezYdKXQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQA/0IUBeq+xyG7Q8Alb -4x6cNgLhyxqyn1JQ856YsrGZrdRXLz3pVv21hKOW5g4ol7kXMnGcpnympgk8bgux -4YFUNxGtM+2SR2ev3bmh+I0UTEom85k6FIYI22cje7cPJUq2E1V/IUWOSPGZ5A8O -HaW0CKOO9aspyYFXZyWqf9pdzygaqSB1BH2yxr8Hqwdhi7YDRE81RYZHC7KMsq7E -f2KkI/Lw+Q4vKGCcXNXiJrkUNkRWiuS8mbUtrNf4ub2i07zkB+pJ6Z5NhqnPV8v8 -nNVqdPmRnDcW1eRedV2Zx8/kUF8xqDjAYAv6i+D4Qmz2wjh63/EkUXqoyn/yrDBL -DGzQWfZvLsXKYPFcEIvGTIkZnKSaLbI5ReO+hZ4i4BgCs/dYvVX27mfTGkwsj11j -w4SmQuMxqMA26HQDhL7TPkBmfzvD53YC57wbioLhAUgQM5pwi3utx8oj+zcoqNxl -x6PiaWCWR0pVjGyI4UTMn2wyf8NlqEa7fJI74S035ZK6eqfP2wfZlzV5zpIOnmR1 -GK7oIjbG2NNVINiOSEhPD9CMYxX6UXh+C3vD37QMdRbcLahvjlFVkPCVi1lPf/Js -Rjj9ZCh2BT/ks2KMIHzR7oFQZzMOiz8MP9HrsS1QLyKMxco2jyI2jL8y/j3VOsZz -3ZkM2dl0vADvHBwHZH3/v/InMA== ------END CERTIFICATE----- diff --git a/vibrator/cs40l26/apex/file_contexts b/vibrator/cs40l26/apex/file_contexts deleted file mode 100644 index 5795d2b5..00000000 --- a/vibrator/cs40l26/apex/file_contexts +++ /dev/null @@ -1,3 +0,0 @@ -(/.*)? u:object_r:vendor_file:s0 -/bin/hw/android\.hardware\.vibrator-service\.cs40l26 u:object_r:hal_vibrator_default_exec:s0 - diff --git a/vibrator/cs40l26/device.mk b/vibrator/cs40l26/device.mk index 24d68d2c..b83f3bb7 100644 --- a/vibrator/cs40l26/device.mk +++ b/vibrator/cs40l26/device.mk @@ -1,8 +1,4 @@ -ifeq ($(LOCAL_PREFER_VENDOR_APEX),true) -PRODUCT_PACKAGES += com.google.pixel.vibrator.hal -else PRODUCT_PACKAGES += android.hardware.vibrator-service.cs40l26 -endif BOARD_SEPOLICY_DIRS += \ hardware/google/pixel-sepolicy/vibrator/common \ diff --git a/vibrator/cs40l26/tests/mocks.h b/vibrator/cs40l26/tests/mocks.h index dda31f24..53c9a045 100644 --- a/vibrator/cs40l26/tests/mocks.h +++ b/vibrator/cs40l26/tests/mocks.h @@ -49,6 +49,8 @@ class MockApi : public ::aidl::android::hardware::vibrator::Vibrator::HwApi { bool(const uint8_t *owtData, const uint32_t numBytes, struct ff_effect *effect, uint32_t *outEffectIndex, int *status)); MOCK_METHOD2(eraseOwtEffect, bool(int8_t effectIndex, std::vector<ff_effect> *effect)); + MOCK_METHOD0(isDbcSupported, bool()); + MOCK_METHOD0(enableDbc, bool()); MOCK_METHOD1(debug, void(int fd)); ~MockApi() override { destructor(); }; diff --git a/vibrator/cs40l26/tests/test-vibrator.cpp b/vibrator/cs40l26/tests/test-vibrator.cpp index ce9808bd..254a6bdb 100644 --- a/vibrator/cs40l26/tests/test-vibrator.cpp +++ b/vibrator/cs40l26/tests/test-vibrator.cpp @@ -88,7 +88,7 @@ static const std::map<Effect, EffectIndex> EFFECT_INDEX{ static constexpr uint32_t MIN_ON_OFF_INTERVAL_US = 8500; static constexpr uint8_t VOLTAGE_SCALE_MAX = 100; static constexpr int8_t MAX_COLD_START_LATENCY_MS = 6; // I2C Transaction + DSP Return-From-Standby -static constexpr auto POLLING_TIMEOUT = 20; +static constexpr auto POLLING_TIMEOUT = 50; // POLLING_TIMEOUT < ASYNC_COMPLETION_TIMEOUT enum WaveformIndex : uint16_t { /* Physical waveform */ WAVEFORM_LONG_VIBRATION_EFFECT_INDEX = 0, @@ -303,6 +303,7 @@ class VibratorTest : public Test { EXPECT_CALL(*mMockApi, setMinOnOffInterval(_)).Times(times); EXPECT_CALL(*mMockApi, getHapticAlsaDevice(_, _)).Times(times); EXPECT_CALL(*mMockApi, setHapticPcmAmp(_, _, _, _)).Times(times); + EXPECT_CALL(*mMockApi, enableDbc()).Times(times); EXPECT_CALL(*mMockApi, debug(_)).Times(times); @@ -396,6 +397,7 @@ TEST_F(VibratorTest, Constructor) { EXPECT_CALL(*mMockApi, getContextSettlingTime()).WillRepeatedly(Return(0)); EXPECT_CALL(*mMockApi, getContextCooldownTime()).WillRepeatedly(Return(0)); EXPECT_CALL(*mMockApi, getContextFadeEnable()).WillRepeatedly(Return(false)); + EXPECT_CALL(*mMockApi, enableDbc()).WillOnce(Return(true)); createVibrator(std::move(mockapi), std::move(mockcal), std::move(mockstats), false); } diff --git a/vibrator/drv2624/apex/Android.bp b/vibrator/drv2624/apex/Android.bp deleted file mode 100644 index 016a7935..00000000 --- a/vibrator/drv2624/apex/Android.bp +++ /dev/null @@ -1,59 +0,0 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -apex { - name: "com.android.vibrator.drv2624", - manifest: "apex_manifest.json", - key: "com.android.vibrator.drv2624.key", - certificate: ":com.android.vibrator.drv2624.certificate", - file_contexts: "file_contexts", - use_vndk_as_stable: true, - updatable: false, - - // install the apex in /vendor/apex - proprietary: true, - - // BEGIN of apex payloads - // /bin - binaries: [ - "android.hardware.vibrator-service.drv2624", - ], - // /etc - prebuilts: [ - "com.android.vibrator.drv2624.rc", - ], - // END of apex payloads - - // BEGIN of companion files to be installed if this module is installed - // init script, which is installed in /vendor/etc. - // Note that init scripts in an apex can contain only "service" sections. - // The following init script contains "on" section to enable the service. - init_rc: [ - "com.android.vibrator.drv2624.enable.rc", - ], - - // vintf manifest fragments, which is installed in /vendor/etc/vintf. - // TODO(b/130058564): should we put vintf framgments within the apex? - vintf_fragments: [ - "com.android.vibrator.drv2624.xml", - ], - // END of companion filse -} - -apex_key { - name: "com.android.vibrator.drv2624.key", - public_key: "com.android.vibrator.drv2624.pubkey", - private_key: "com.android.vibrator.drv2624.pem", -} - -android_app_certificate { - name: "com.android.vibrator.drv2624.certificate", - certificate: "com.android.vibrator.drv2624", -} - -prebuilt_etc { - name: "com.android.vibrator.drv2624.rc", - src: "com.android.vibrator.drv2624.rc", - installable: false, -} diff --git a/vibrator/drv2624/apex/apex_manifest.json b/vibrator/drv2624/apex/apex_manifest.json deleted file mode 100644 index ac8af3a4..00000000 --- a/vibrator/drv2624/apex/apex_manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.android.vibrator.drv2624", - "version": 1 -} diff --git a/vibrator/drv2624/apex/com.android.vibrator.drv2624.enable.rc b/vibrator/drv2624/apex/com.android.vibrator.drv2624.enable.rc deleted file mode 100644 index d9b79f08..00000000 --- a/vibrator/drv2624/apex/com.android.vibrator.drv2624.enable.rc +++ /dev/null @@ -1,29 +0,0 @@ -on boot - wait /sys/class/leds/vibrator/device - - mkdir /mnt/vendor/persist/haptics 0770 system system - chmod 770 /mnt/vendor/persist/haptics - chmod 440 /mnt/vendor/persist/haptics/drv2624.cal - chown system system /mnt/vendor/persist/haptics - chown system system /mnt/vendor/persist/haptics/drv2624.cal - - write /sys/class/leds/vibrator/trigger transient - chown system system /sys/class/leds/vibrator/activate - chown system system /sys/class/leds/vibrator/brightness - chown system system /sys/class/leds/vibrator/duration - chown system system /sys/class/leds/vibrator/state - - chown system system /sys/class/leds/vibrator/device/autocal - chown system system /sys/class/leds/vibrator/device/autocal_result - chown system system /sys/class/leds/vibrator/device/ctrl_loop - chown system system /sys/class/leds/vibrator/device/lp_trigger_effect - chown system system /sys/class/leds/vibrator/device/lp_trigger_scale - chown system system /sys/class/leds/vibrator/device/lra_wave_shape - chown system system /sys/class/leds/vibrator/device/mode - chown system system /sys/class/leds/vibrator/device/od_clamp - chown system system /sys/class/leds/vibrator/device/ol_lra_period - chown system system /sys/class/leds/vibrator/device/rtp_input - chown system system /sys/class/leds/vibrator/device/scale - chown system system /sys/class/leds/vibrator/device/set_sequencer - - enable vendor.vibrator.drv2624 diff --git a/vibrator/drv2624/apex/com.android.vibrator.drv2624.pem b/vibrator/drv2624/apex/com.android.vibrator.drv2624.pem deleted file mode 100644 index 012ed8fc..00000000 --- a/vibrator/drv2624/apex/com.android.vibrator.drv2624.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/vibrator/drv2624/apex/com.android.vibrator.drv2624.pk8 b/vibrator/drv2624/apex/com.android.vibrator.drv2624.pk8 Binary files differdeleted file mode 100644 index 1e941879..00000000 --- a/vibrator/drv2624/apex/com.android.vibrator.drv2624.pk8 +++ /dev/null diff --git a/vibrator/drv2624/apex/com.android.vibrator.drv2624.pubkey b/vibrator/drv2624/apex/com.android.vibrator.drv2624.pubkey Binary files differdeleted file mode 100644 index 479a8686..00000000 --- a/vibrator/drv2624/apex/com.android.vibrator.drv2624.pubkey +++ /dev/null diff --git a/vibrator/drv2624/apex/com.android.vibrator.drv2624.rc b/vibrator/drv2624/apex/com.android.vibrator.drv2624.rc deleted file mode 100644 index df4e3e95..00000000 --- a/vibrator/drv2624/apex/com.android.vibrator.drv2624.rc +++ /dev/null @@ -1,18 +0,0 @@ -service vendor.vibrator.drv2624 /apex/com.android.vibrator.drv2624/bin/hw/android.hardware.vibrator-service.drv2624 - class hal - user system - group system - - setenv PROPERTY_PREFIX ro.vendor.vibrator.hal. - setenv CALIBRATION_FILEPATH /persist/haptics/drv2624.cal - - setenv HWAPI_PATH_PREFIX /sys/class/leds/vibrator/ - setenv HWAPI_DEBUG_PATHS " - device/autocal - device/lp_trigger_effect - device/lp_trigger_scale - device/ol_lra_period - state - " - - disabled diff --git a/vibrator/drv2624/apex/com.android.vibrator.drv2624.x509.pem b/vibrator/drv2624/apex/com.android.vibrator.drv2624.x509.pem deleted file mode 100644 index e1d9cac2..00000000 --- a/vibrator/drv2624/apex/com.android.vibrator.drv2624.x509.pem +++ /dev/null @@ -1,34 +0,0 @@ ------BEGIN CERTIFICATE----- -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 -8rWXShiHxat5sB1c3ON8X4ZukajREniUSOXhzic= ------END CERTIFICATE----- diff --git a/vibrator/drv2624/apex/com.android.vibrator.drv2624.xml b/vibrator/drv2624/apex/com.android.vibrator.drv2624.xml deleted file mode 100644 index 4db8f8c5..00000000 --- a/vibrator/drv2624/apex/com.android.vibrator.drv2624.xml +++ /dev/null @@ -1,7 +0,0 @@ -<manifest version="1.0" type="device"> - <hal format="aidl"> - <name>android.hardware.vibrator</name> - <version>2</version> - <fqname>IVibrator/default</fqname> - </hal> -</manifest> diff --git a/vibrator/drv2624/apex/file_contexts b/vibrator/drv2624/apex/file_contexts deleted file mode 100644 index 5be98ec7..00000000 --- a/vibrator/drv2624/apex/file_contexts +++ /dev/null @@ -1,2 +0,0 @@ -(/.*)? u:object_r:vendor_file:s0 -/bin/hw/android\.hardware\.vibrator-service\.drv2624 u:object_r:hal_vibrator_default_exec:s0
\ No newline at end of file diff --git a/vibrator/drv2624/apex/key.pem b/vibrator/drv2624/apex/key.pem deleted file mode 100644 index b582099c..00000000 --- a/vibrator/drv2624/apex/key.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -zCK8JO9WGOwvH9n0F+pgYXEo4OtjMA== ------END PRIVATE KEY----- |