diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-10-19 03:44:51 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-10-19 03:44:51 +0000 |
commit | c2332b1acc1eb3efd4ae364b2c8e41d200d1fffc (patch) | |
tree | 4a14e034e636acc64ad4f7ca306bd747115d0a34 | |
parent | c3f45dc3f123b615c1328c8c7b488d06ae6943c7 (diff) | |
parent | dad6bbcb3ff7e96e479958636b29d15e2591d831 (diff) | |
download | pixel-gki13-boot-release.tar.gz |
Snap for 9192524 from dad6bbcb3ff7e96e479958636b29d15e2591d831 to gki13-boot-releasegki13-boot-release
Change-Id: I228dbae04cd5058b3672f144d357b4ce8fcf4ead
-rw-r--r-- | battery_mitigation/Android.bp | 47 | ||||
-rw-r--r-- | battery_mitigation/BatteryMitigation.cpp | 32 | ||||
-rw-r--r-- | battery_mitigation/MitigationThermalManager.cpp | 187 | ||||
-rw-r--r-- | battery_mitigation/OWNERS | 2 | ||||
-rw-r--r-- | battery_mitigation/include/battery_mitigation/BatteryMitigation.h | 39 | ||||
-rw-r--r-- | battery_mitigation/include/battery_mitigation/MitigationConfig.h | 48 | ||||
-rw-r--r-- | battery_mitigation/include/battery_mitigation/MitigationThermalManager.h | 125 | ||||
-rw-r--r-- | fastboot/Fastboot.cpp | 49 | ||||
-rw-r--r-- | power-libperfmgr/aidl/PowerHintSession.cpp | 12 | ||||
-rw-r--r-- | powerstats/android.hardware.power.stats-service.pixel.rc | 14 | ||||
-rw-r--r-- | vibrator/cs40l26/Vibrator.cpp | 239 | ||||
-rw-r--r-- | vibrator/cs40l26/Vibrator.h | 5 | ||||
-rw-r--r-- | vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual.rc | 2 | ||||
-rw-r--r-- | vibrator/cs40l26/android.hardware.vibrator-service.cs40l26.rc | 2 |
14 files changed, 676 insertions, 127 deletions
diff --git a/battery_mitigation/Android.bp b/battery_mitigation/Android.bp new file mode 100644 index 00000000..19d6c4dd --- /dev/null +++ b/battery_mitigation/Android.bp @@ -0,0 +1,47 @@ +// +// 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"], +} + +cc_library { + name: "libpixelmitigation", + export_include_dirs: ["include"], + vendor_available: true, + srcs: [ + "BatteryMitigation.cpp", + "MitigationThermalManager.cpp", + ], + static_libs: [ + "libmath", + ], + + shared_libs: [ + "libbase", + "libbinder_ndk", + "libcutils", + "libhardware", + "libhidlbase", + "liblog", + "libutils", + "android.hardware.thermal@2.0" + ], + cflags: [ + "-Wall", + "-Werror", + ], +} diff --git a/battery_mitigation/BatteryMitigation.cpp b/battery_mitigation/BatteryMitigation.cpp new file mode 100644 index 00000000..252b1eec --- /dev/null +++ b/battery_mitigation/BatteryMitigation.cpp @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include <battery_mitigation/BatteryMitigation.h> + +namespace android { +namespace hardware { +namespace google { +namespace pixel { + +BatteryMitigation::BatteryMitigation(const struct MitigationConfig::Config &cfg) { + mThermalMgr = &MitigationThermalManager::getInstance(); + mThermalMgr->updateConfig(cfg); +} + +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android diff --git a/battery_mitigation/MitigationThermalManager.cpp b/battery_mitigation/MitigationThermalManager.cpp new file mode 100644 index 00000000..b1320e70 --- /dev/null +++ b/battery_mitigation/MitigationThermalManager.cpp @@ -0,0 +1,187 @@ +/* + * 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. + */ +#define LOG_TAG "mitigation-logger" + +#include <battery_mitigation/MitigationThermalManager.h> + +#include <android-base/chrono_utils.h> +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/parseint.h> +#include <android-base/properties.h> +#include <android-base/strings.h> +#include <errno.h> +#include <sys/time.h> + +#include <chrono> +#include <cmath> +#include <ctime> +#include <iomanip> +#include <iostream> +#include <string> + +#define NUM_OF_SAMPLES 20 +#define CAPTURE_INTERVAL_S 2 /* 2 seconds between new capture */ + +namespace android { +namespace hardware { +namespace google { +namespace pixel { + +using android::hardware::thermal::V1_0::ThermalStatus; +using android::hardware::thermal::V1_0::ThermalStatusCode; + +MitigationThermalManager &MitigationThermalManager::getInstance() { + static MitigationThermalManager mitigationThermalManager; + return mitigationThermalManager; +} + +void MitigationThermalManager::remove() { + if (!thermal) { + return; + } + if (callback) { + ThermalStatus returnStatus; + auto ret = thermal->unregisterThermalChangedCallback( + callback, [&returnStatus](ThermalStatus status) { returnStatus = status; }); + if (!ret.isOk() || returnStatus.code != ThermalStatusCode::SUCCESS) { + LOG(ERROR) << "Failed to release thermal callback!"; + } + } + if (deathRecipient) { + auto ret = thermal->unlinkToDeath(deathRecipient); + if (!ret.isOk()) { + LOG(ERROR) << "Failed to release thermal death notification!"; + } + } +} + +MitigationThermalManager::MitigationThermalManager() { + if (!connectThermalHal()) { + remove(); + } +} + +MitigationThermalManager::~MitigationThermalManager() { + remove(); +} + +void MitigationThermalManager::updateConfig(const struct MitigationConfig::Config &cfg) { + kLogFilePath = std::string(cfg.LogFilePath); + kSystemPath = cfg.SystemPath; + kSystemName = cfg.SystemName; + kFilteredZones = cfg.FilteredZones; +} + +bool MitigationThermalManager::connectThermalHal() { + thermal = IThermal::getService(); + if (thermal) { + lastCapturedTime = ::android::base::boot_clock::now(); + registerCallback(); + return true; + } else { + LOG(ERROR) << "Cannot get IThermal service!"; + } + return false; +} + +bool MitigationThermalManager::isMitigationTemperature(const Temperature &temperature) { + if (std::find(kFilteredZones.begin(), kFilteredZones.end(), temperature.name) != + kFilteredZones.end()) { + return true; + } + return false; +} + +void MitigationThermalManager::thermalCb(const Temperature &temperature) { + if ((temperature.throttlingStatus == ThrottlingSeverity::NONE) || + (!isMitigationTemperature(temperature))) { + return; + } + auto currentTime = ::android::base::boot_clock::now(); + auto delta = + std::chrono::duration_cast<std::chrono::seconds>(currentTime - lastCapturedTime); + if (delta.count() < CAPTURE_INTERVAL_S) { + /* Do not log if delta is within 2 seconds */ + return; + } + int flag = O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_APPEND | O_TRUNC; + android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(kLogFilePath.c_str(), flag, 0644))); + lastCapturedTime = currentTime; + std::stringstream oss; + oss << temperature.name << " triggered at " << temperature.value << std::endl << std::flush; + android::base::WriteStringToFd(oss.str(), fd); + + for (int i = 0; i < NUM_OF_SAMPLES; i++) { + auto now = std::chrono::system_clock::now(); + auto time_sec = std::chrono::system_clock::to_time_t(now); + auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) - + std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()); + struct tm now_tm; + localtime_r(&time_sec, &now_tm); + oss << std::put_time(&now_tm, "%m-%d %H:%M:%S.") << std::setw(3) << std::setfill('0') + << ms.count() << std::endl << std::flush; + android::base::WriteStringToFd(oss.str(), fd); + oss.str(""); + /* log System info */ + for (int j = 0; j < kSystemName.size(); j++) { + std::string value; + bool result = android::base::ReadFileToString(kSystemPath[j], &value); + if (!result) { + LOG(ERROR) << "Could not read: " << kSystemName[j]; + } + android::base::WriteStringToFd(kSystemName[j] + ":" + value, fd); + } + } + fsync(fd); +} + +void MitigationThermalManager::registerCallback() { + if (!thermal) { + LOG(ERROR) << "Cannot register thermal callback!"; + return; + } + ThermalStatus returnStatus; + // Create thermal death recipient object. + if (deathRecipient == nullptr) { + deathRecipient = new MitigationThermalManager::ThermalDeathRecipient(); + } + // Create thermal callback recipient object. + if (callback == nullptr) { + callback = new MitigationThermalManager::ThermalCallback( + [this](const Temperature &temperature) { + std::lock_guard api_lock(mutex_); + thermalCb(temperature); + }); + } + // Register thermal callback SKIN to thermal hal to cover all. Cannot register twice. + auto ret_callback = thermal->registerThermalChangedCallback( + callback, false, TemperatureType::SKIN, + [&returnStatus](ThermalStatus status) { return returnStatus = status; }); + if (!ret_callback.isOk() || returnStatus.code != ThermalStatusCode::SUCCESS) { + LOG(ERROR) << "Failed to register thermal callback!"; + } + // Register thermal death notification to thermal hal. + auto retLink = thermal->linkToDeath(deathRecipient, 0); + if (!retLink.isOk()) { + LOG(ERROR) << "Failed to register thermal death notification!"; + } +} + +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android diff --git a/battery_mitigation/OWNERS b/battery_mitigation/OWNERS new file mode 100644 index 00000000..363efac2 --- /dev/null +++ b/battery_mitigation/OWNERS @@ -0,0 +1,2 @@ +geolee@google.com +wvw@google.com diff --git a/battery_mitigation/include/battery_mitigation/BatteryMitigation.h b/battery_mitigation/include/battery_mitigation/BatteryMitigation.h new file mode 100644 index 00000000..86dda064 --- /dev/null +++ b/battery_mitigation/include/battery_mitigation/BatteryMitigation.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#pragma once + +#include "MitigationThermalManager.h" + +namespace android { +namespace hardware { +namespace google { +namespace pixel { + +using ::android::sp; + +class BatteryMitigation : public RefBase { + public: + BatteryMitigation(const struct MitigationConfig::Config &cfg); + + private: + MitigationThermalManager *mThermalMgr; +}; + +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android diff --git a/battery_mitigation/include/battery_mitigation/MitigationConfig.h b/battery_mitigation/include/battery_mitigation/MitigationConfig.h new file mode 100644 index 00000000..36a4f5e6 --- /dev/null +++ b/battery_mitigation/include/battery_mitigation/MitigationConfig.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#ifndef HARDWARE_GOOGLE_PIXEL_BATTERY_MITIGATION_CONFIG_H +#define HARDWARE_GOOGLE_PIXEL_BATTERY_MITIGATION_CONFIG_H + +namespace android { +namespace hardware { +namespace google { +namespace pixel { + +class MitigationConfig { + public: + struct Config { + const std::vector<std::string> SystemPath; + const std::vector<std::string> FilteredZones; + const std::vector<std::string> SystemName; + const char *const LogFilePath; + }; + + MitigationConfig(const struct Config &cfg); + + private: + const std::vector<std::string> kSystemPath; + const std::vector<std::string> kFilteredZones; + const std::vector<std::string> kSystemName; + const char *const kLogFilePath; +}; + +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android + +#endif // HARDWARE_GOOGLE_PIXEL_BATTERY_MITIGATION_CONFIG_H diff --git a/battery_mitigation/include/battery_mitigation/MitigationThermalManager.h b/battery_mitigation/include/battery_mitigation/MitigationThermalManager.h new file mode 100644 index 00000000..5c4ddbe7 --- /dev/null +++ b/battery_mitigation/include/battery_mitigation/MitigationThermalManager.h @@ -0,0 +1,125 @@ +/* + * 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. + */ + +#pragma once + +#ifndef MITIGATION_THERMAL_MANAGER_H_ +#define MITIGATION_THERMAL_MANAGER_H_ + +#include <android-base/chrono_utils.h> +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/parseint.h> +#include <android-base/properties.h> +#include <android-base/strings.h> +#include <android/hardware/thermal/2.0/IThermal.h> +#include <android/hardware/thermal/2.0/IThermalChangedCallback.h> +#include <android/hardware/thermal/2.0/types.h> +#include <unistd.h> +#include <utils/Mutex.h> + +#include "MitigationConfig.h" + +#include <fstream> +#include <iostream> + +namespace android { +namespace hardware { +namespace google { +namespace pixel { + +using android::hardware::google::pixel::MitigationConfig; +using android::hardware::hidl_death_recipient; +using android::hardware::hidl_string; +using android::hardware::Return; +using android::hardware::thermal::V2_0::IThermal; +using android::hardware::thermal::V2_0::IThermalChangedCallback; +using android::hardware::thermal::V2_0::Temperature; +using android::hardware::thermal::V2_0::TemperatureType; +using android::hardware::thermal::V2_0::ThrottlingSeverity; +using android::hardware::Void; + +class MitigationThermalManager { + public: + static MitigationThermalManager &getInstance(); + + // delete copy and move constructors and assign operators + MitigationThermalManager(MitigationThermalManager const &) = delete; + MitigationThermalManager(MitigationThermalManager &&) = delete; + MitigationThermalManager &operator=(MitigationThermalManager const &) = delete; + MitigationThermalManager &operator=(MitigationThermalManager &&) = delete; + + private: + // ThermalCallback implements the HIDL thermal changed callback + // interface, IThermalChangedCallback. + void thermalCb(const Temperature &temperature); + android::base::boot_clock::time_point lastCapturedTime; + + class ThermalCallback : public IThermalChangedCallback { + public: + ThermalCallback(std::function<void(const Temperature &)> notify_function) + : notifyFunction(notify_function) {} + + // Callback function. thermal service will call this. + Return<void> notifyThrottling(const Temperature &temperature) override { + if ((temperature.type == TemperatureType::BCL_VOLTAGE) || + (temperature.type == TemperatureType::BCL_CURRENT)) { + notifyFunction(temperature); + } + return ::android::hardware::Void(); + } + + private: + std::function<void(const Temperature &)> notifyFunction; + }; + + class ThermalDeathRecipient : virtual public hidl_death_recipient { + public: + void serviceDied(uint64_t /*cookie*/, + const android::wp<::android::hidl::base::V1_0::IBase> & /*who*/) override { + MitigationThermalManager::getInstance().connectThermalHal(); + }; + }; + + public: + MitigationThermalManager(); + ~MitigationThermalManager(); + bool connectThermalHal(); + bool isMitigationTemperature(const Temperature &temperature); + void registerCallback(); + void remove(); + void updateConfig(const struct MitigationConfig::Config &cfg); + + + private: + std::mutex mutex_; + // Thermal hal interface. + android::sp<IThermal> thermal; + // Thermal hal callback object. + android::sp<ThermalCallback> callback; + // Receiver when thermal hal restart. + android::sp<ThermalDeathRecipient> deathRecipient; + std::vector<std::string> kSystemPath; + std::vector<std::string> kFilteredZones; + std::vector<std::string> kSystemName; + std::string kLogFilePath; +}; + +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android +#endif diff --git a/fastboot/Fastboot.cpp b/fastboot/Fastboot.cpp index 922334b4..913d82d0 100644 --- a/fastboot/Fastboot.cpp +++ b/fastboot/Fastboot.cpp @@ -16,15 +16,16 @@ #include "fastboot/Fastboot.h" -#include <string> -#include <unordered_map> -#include <vector> -#include <map> - #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/strings.h> #include <android-base/unique_fd.h> +#include <dlfcn.h> + +#include <map> +#include <string> +#include <unordered_map> +#include <vector> // FS headers #include <ext4_utils/wipe.h> @@ -169,11 +170,35 @@ enum WipeVolumeStatus wipe_volume(const std::string &volume) { return WIPE_OK; } +// Attempt to reuse a WipeKeys function that might be found in the recovery +// library in order to clear any digital car keys on the secure element. +bool WipeDigitalCarKeys(void) { + static constexpr const char *kDefaultLibRecoveryUIExt = "librecovery_ui_ext.so"; + void *librecovery_ui_ext = dlopen(kDefaultLibRecoveryUIExt, RTLD_NOW); + if (librecovery_ui_ext == nullptr) { + // Dynamic library not found. Returning true since this likely + // means target does not support DCK. + return true; + } + + bool *(*WipeKeysFunc)(void *const); + reinterpret_cast<void *&>(WipeKeysFunc) = dlsym(librecovery_ui_ext, "WipeKeys"); + if (WipeKeysFunc == nullptr) { + // No WipeKeys implementation found. Returning true since this likely + // means target does not support DCK. + return true; + } + + return (*WipeKeysFunc)(nullptr); +} + Return<void> Fastboot::doOemSpecificErase(V1_1::IFastboot::doOemSpecificErase_cb _hidl_cb) { // Erase metadata partition along with userdata partition. // Keep erasing Titan M even if failing on this case. auto wipe_status = wipe_volume("/metadata"); + bool dck_wipe_success = WipeDigitalCarKeys(); + // Connect to Titan M ::nos::NuggetClient client; client.Open(); @@ -188,19 +213,27 @@ Return<void> Fastboot::doOemSpecificErase(V1_1::IFastboot::doOemSpecificErase_cb memcpy(magic.data(), &magicValue, sizeof(magicValue)); const uint8_t retry_count = 5; uint32_t nugget_status; - for(uint8_t i = 0; i < retry_count; i++) { + for (uint8_t i = 0; i < retry_count; i++) { nugget_status = client.CallApp(APP_ID_NUGGET, NUGGET_PARAM_NUKE_FROM_ORBIT, magic, nullptr); - if (nugget_status == APP_SUCCESS && wipe_status == WIPE_OK) { + if (nugget_status == APP_SUCCESS && wipe_status == WIPE_OK && dck_wipe_success) { _hidl_cb({Status::SUCCESS, wipe_vol_ret_msg[wipe_status]}); return Void(); } } // Return exactly what happened - if (nugget_status != APP_SUCCESS && wipe_status != WIPE_OK) { + if (nugget_status != APP_SUCCESS && wipe_status != WIPE_OK && !dck_wipe_success) { + _hidl_cb({Status::FAILURE_UNKNOWN, "Fail on wiping metadata, Titan M user data, and DCK"}); + } else if (nugget_status != APP_SUCCESS && wipe_status != WIPE_OK) { _hidl_cb({Status::FAILURE_UNKNOWN, "Fail on wiping metadata and Titan M user data"}); + } else if (nugget_status != APP_SUCCESS && !dck_wipe_success) { + _hidl_cb({Status::FAILURE_UNKNOWN, "Titan M user data and DCK wipe failed"}); } else if (nugget_status != APP_SUCCESS) { _hidl_cb({Status::FAILURE_UNKNOWN, "Titan M user data wipe failed"}); + } else if (wipe_status != WIPE_OK && !dck_wipe_success) { + _hidl_cb({Status::FAILURE_UNKNOWN, "Fail on wiping metadata and DCK"}); + } else if (!dck_wipe_success) { + _hidl_cb({Status::FAILURE_UNKNOWN, "DCK wipe failed"}); } else { if (wipe_vol_ret_msg.find(wipe_status) != wipe_vol_ret_msg.end()) _hidl_cb({Status::FAILURE_UNKNOWN, wipe_vol_ret_msg[wipe_status]}); diff --git a/power-libperfmgr/aidl/PowerHintSession.cpp b/power-libperfmgr/aidl/PowerHintSession.cpp index cac641a6..7998c538 100644 --- a/power-libperfmgr/aidl/PowerHintSession.cpp +++ b/power-libperfmgr/aidl/PowerHintSession.cpp @@ -414,9 +414,16 @@ void PowerHintSession::setStale() { void PowerHintSession::wakeup() { std::lock_guard<std::mutex> guard(mSessionLock); - // We only wake up non-paused and stale sessions - if (mSessionClosed || !isActive() || !isTimeout()) + // We only wake up non-paused session + if (mSessionClosed || !isActive()) { return; + } + // Update session's timer + mStaleTimerHandler->updateTimer(); + // Skip uclamp update for stale session + if (!isTimeout()) { + return; + } if (ATRACE_ENABLED()) { std::string tag = StringPrintf("wakeup.%s(a:%d,s:%d)", getIdString().c_str(), isActive(), isTimeout()); @@ -426,7 +433,6 @@ void PowerHintSession::wakeup() { int min = std::max(mDescriptor->current_min, static_cast<int>(adpfConfig->mUclampMinInit)); mDescriptor->current_min = min; PowerSessionManager::getInstance()->setUclampMinLocked(this, min); - mStaleTimerHandler->updateTimer(); if (ATRACE_ENABLED()) { const std::string idstr = getIdString(); diff --git a/powerstats/android.hardware.power.stats-service.pixel.rc b/powerstats/android.hardware.power.stats-service.pixel.rc index f5e49f23..01ec05ca 100644 --- a/powerstats/android.hardware.power.stats-service.pixel.rc +++ b/powerstats/android.hardware.power.stats-service.pixel.rc @@ -1,3 +1,17 @@ +# ODPM: change VSYS_PWR_MMWAVE to S9M_LLDO3 on sub6 device +# detail: b/231463665#10 +on early-boot && property:ro.boot.hardware.sku=GP4BC + write /sys/bus/iio/devices/iio:device0/enabled_rails "CH0=BUCK9M" + +on early-boot && property:ro.boot.hardware.sku=GFE4J + write /sys/bus/iio/devices/iio:device0/enabled_rails "CH0=BUCK9M" + +on early-boot && property:ro.boot.hardware.sku=GVU6C + write /sys/bus/iio/devices/iio:device0/enabled_rails "CH0=BUCK9M" + +on early-boot && property:ro.boot.hardware.sku=G03Z5 + write /sys/bus/iio/devices/iio:device0/enabled_rails "CH0=BUCK9M" + service vendor.power.stats /vendor/bin/hw/android.hardware.power.stats-service.pixel class hal user system diff --git a/vibrator/cs40l26/Vibrator.cpp b/vibrator/cs40l26/Vibrator.cpp index 587f0fe4..c6324c7d 100644 --- a/vibrator/cs40l26/Vibrator.cpp +++ b/vibrator/cs40l26/Vibrator.cpp @@ -19,7 +19,6 @@ #include <glob.h> #include <hardware/hardware.h> #include <hardware/vibrator.h> -#include <linux/input.h> #include <log/log.h> #include <stdio.h> #include <utils/Trace.h> @@ -234,8 +233,6 @@ static int dspmem_chunk_flush(struct dspmem_chunk *ch) { return dspmem_chunk_write(ch, 24 - ch->cachebits, 0); } -std::vector<struct ff_effect> mFfEffects; - Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal) : mHwApi(std::move(hwapi)), mHwCal(std::move(hwcal)), mAsyncHandle(std::async([] {})) { int32_t longFrequencyShift; @@ -284,26 +281,16 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal) return; } - /* - * Create custom effects for all physical waveforms. - * 1. Set the initial duration for the corresponding RAM waveform. - * 2. Write to the force feedback driver. If the waveform firmware is not loaded, - * retry at most 10 times and then abort the constructor. - * 3. Store the effect ID. - */ - uint8_t retry = 0; mFfEffects.resize(WAVEFORM_MAX_INDEX); mEffectDurations.resize(WAVEFORM_MAX_INDEX); mEffectDurations = { 1000, 100, 30, 1000, 300, 130, 150, 500, 100, 15, 20, 1000, 1000, 1000, }; /* 11+3 waveforms. The duration must < UINT16_MAX */ - uint8_t effectIndex = 0; - const uint8_t owtPlaceholder[] = {0x00, 0x00, 0x01, 0x00, 0x00, 0x5F, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}; - const uint8_t owtPlaceholderLength = sizeof(owtPlaceholder); + uint8_t effectIndex; for (effectIndex = 0; effectIndex < WAVEFORM_MAX_INDEX; effectIndex++) { if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) { + /* Initialize physical waveforms. */ mFfEffects[effectIndex] = { .type = FF_PERIODIC, .id = -1, @@ -312,6 +299,13 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal) .u.periodic.custom_data = new int16_t[2]{RAM_WVFRM_BANK, effectIndex}, .u.periodic.custom_len = FF_CUSTOM_DATA_LEN, }; + + if (ioctl(mInputFd, EVIOCSFF, &mFfEffects[effectIndex]) < 0) { + ALOGE("Failed upload effect %d (%d): %s", effectIndex, errno, strerror(errno)); + } + if (mFfEffects[effectIndex].id != effectIndex) { + ALOGW("Unexpected effect index: %d -> %d", effectIndex, mFfEffects[effectIndex].id); + } } else { /* Initiate placeholders for OWT effects. */ mFfEffects[effectIndex] = { @@ -320,35 +314,10 @@ Vibrator::Vibrator(std::unique_ptr<HwApi> hwapi, std::unique_ptr<HwCal> hwcal) .replay.length = 0, .u.periodic.waveform = FF_CUSTOM, .u.periodic.custom_data = nullptr, - .u.periodic.custom_len = owtPlaceholderLength / sizeof(int16_t), + .u.periodic.custom_len = 0, }; - mFfEffects[effectIndex].u.periodic.custom_data = - new int16_t[mFfEffects[effectIndex].u.periodic.custom_len]{0x0000}; - memcpy(mFfEffects[effectIndex].u.periodic.custom_data, owtPlaceholder, - owtPlaceholderLength); - } - - while (true) { - if (ioctl(mInputFd, EVIOCSFF, &mFfEffects[effectIndex]) < 0) { - ALOGE("Failed upload effect %d (%d): %s", effectIndex, errno, strerror(errno)); - - if (retry < 10) { - sleep(1); - ALOGW("Retry #%u", ++retry); - continue; - } else { - ALOGE("Retried but the initialization was failed!"); - return; - } - } - mFfEffects[effectIndex].id = effectIndex; - break; } } - if (effectIndex != WAVEFORM_MAX_INDEX) { - ALOGE("Incomplete effect initialization!"); - return; - } if (mHwCal->getF0(&caldata)) { mHwApi->setF0(caldata); @@ -434,6 +403,7 @@ ndk::ScopedAStatus Vibrator::off() { .value = 0, }; + /* Stop the active effect. */ if (write(mInputFd, (const void *)&play, sizeof(play)) != sizeof(play)) { ALOGE("Failed to stop effect %d (%d): %s", play.code, errno, strerror(errno)); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); @@ -441,7 +411,14 @@ ndk::ScopedAStatus Vibrator::off() { mActiveId = -1; setGlobalAmplitude(false); - mHwApi->setF0Offset(0); + if (mF0Offset) { + mHwApi->setF0Offset(0); + } + + if (play.code >= WAVEFORM_MAX_PHYSICAL_INDEX) { + eraseOwtEffect(play.code); + } + return ndk::ScopedAStatus::ok(); } @@ -458,8 +435,10 @@ ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, timeoutMs += MAX_COLD_START_LATENCY_MS; } setGlobalAmplitude(true); - mHwApi->setF0Offset(mF0Offset); - return on(timeoutMs, index, callback); + if (mF0Offset) { + mHwApi->setF0Offset(mF0Offset); + } + return on(timeoutMs, index, nullptr /*ignored*/, callback); } ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength, @@ -564,7 +543,7 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi dspmem_chunk_write(ch, 8, 0); /* Padding */ dspmem_chunk_write(ch, 8, (uint8_t)(0xFF & size)); /* nsections */ dspmem_chunk_write(ch, 8, 0); /* repeat */ - uint8_t header_count = ch->bytes; + uint8_t header_count = dspmem_chunk_bytes(ch); /* Insert 1 section for a wait before the first effect. */ if (nextEffectDelay) { @@ -612,50 +591,66 @@ ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect> &composi dspmem_chunk_write(ch, 16, (uint16_t)(0xFFFF & nextEffectDelay)); /* delay */ } dspmem_chunk_flush(ch); - if (header_count == ch->bytes) { + if (header_count == dspmem_chunk_bytes(ch)) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } else { - return performEffect(0 /*ignored*/, 0 /*ignored*/, ch, callback); + return performEffect(WAVEFORM_MAX_INDEX /*ignored*/, VOLTAGE_SCALE_MAX /*ignored*/, ch, + callback); } } -ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, +ndk::ScopedAStatus Vibrator::on(uint32_t timeoutMs, uint32_t effectIndex, dspmem_chunk *ch, const std::shared_ptr<IVibratorCallback> &callback) { - if (effectIndex >= WAVEFORM_MAX_INDEX) { + ndk::ScopedAStatus status = ndk::ScopedAStatus::ok(); + struct input_event play = { + .type = EV_FF, + .value = 1, + }; + + if (effectIndex >= FF_MAX_EFFECTS) { ALOGE("Invalid waveform index %d", effectIndex); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + goto end; } if (mAsyncHandle.wait_for(ASYNC_COMPLETION_TIMEOUT) != std::future_status::ready) { ALOGE("Previous vibration pending: prev: %d, curr: %d", mActiveId, effectIndex); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + goto end; } - /* Update duration for long/short vibration. */ - if (effectIndex == WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX || - effectIndex == WAVEFORM_LONG_VIBRATION_EFFECT_INDEX) { + if (ch) { + /* Upload OWT effect. */ + effectIndex = 0; + status = uploadOwtEffect(ch->head, dspmem_chunk_bytes(ch), &effectIndex); + delete ch; + + if (!status.isOk()) { + goto end; + } + } else if (effectIndex == WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX || + effectIndex == WAVEFORM_LONG_VIBRATION_EFFECT_INDEX) { + /* Update duration for long/short vibration. */ mFfEffects[effectIndex].replay.length = static_cast<uint16_t>(timeoutMs); if (ioctl(mInputFd, EVIOCSFF, &mFfEffects[effectIndex]) < 0) { ALOGE("Failed to edit effect %d (%d): %s", effectIndex, errno, strerror(errno)); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + goto end; } } + play.code = effectIndex; + mActiveId = play.code; /* Play the event now. */ - struct input_event play = { - .type = EV_FF, - .code = static_cast<uint16_t>(effectIndex), - .value = 1, - }; if (write(mInputFd, (const void *)&play, sizeof(play)) != sizeof(play)) { ALOGE("Failed to play effect %d (%d): %s", play.code, errno, strerror(errno)); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + status = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + goto end; } - mActiveId = play.code; - mAsyncHandle = std::async(&Vibrator::waitForComplete, this, callback); - return ndk::ScopedAStatus::ok(); +end: + return status; } ndk::ScopedAStatus Vibrator::setEffectAmplitude(float amplitude, float maximum) { @@ -1020,7 +1015,8 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &compo /* Update nsections */ updateNSection(ch, segmentIdx); - return performEffect(0 /*ignored*/, 0 /*ignored*/, ch, callback); + return performEffect(WAVEFORM_MAX_INDEX /*ignored*/, VOLTAGE_SCALE_MAX /*ignored*/, ch, + callback); } bool Vibrator::isUnderExternalControl() { @@ -1310,7 +1306,7 @@ ndk::ScopedAStatus Vibrator::getPrimitiveDetails(CompositePrimitive primitive, ndk::ScopedAStatus Vibrator::uploadOwtEffect(uint8_t *owtData, uint32_t numBytes, uint32_t *outEffectIndex) { if (owtData == nullptr) { - ALOGE("Invalid waveform bank"); + ALOGE("Invalid OWT data"); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } @@ -1320,7 +1316,7 @@ ndk::ScopedAStatus Vibrator::uploadOwtEffect(uint8_t *owtData, uint32_t numBytes uint32_t freeBytes; mHwApi->getOwtFreeSpace(&freeBytes); if (numBytes > freeBytes) { - ALOGE("Effect %d length: %d > %d!", targetId, numBytes, freeBytes); + ALOGE("Invalid OWT length: Effect %d: %d > %d!", targetId, numBytes, freeBytes); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } @@ -1334,44 +1330,64 @@ ndk::ScopedAStatus Vibrator::uploadOwtEffect(uint8_t *owtData, uint32_t numBytes } memcpy(mFfEffects[targetId].u.periodic.custom_data, owtData, numBytes); - /* - * Erase the created OWT waveform. If no error, the HAL, ff-core and haptics driver effect lists - * are properly aligned. Hence, proceed to add a new effect to play. If failed, scanarios are as - * follows: - * 1. ENOMEM 12 Out of memory: - * Driver effect list is empty while HAL and ff-cores' are not. - * Effect editing can add the OWT effect to driver while keep the original effect ID. - * 2. EACCES 13 Permission denied: - * Effect was created by others or previous HAL instance (HAL got restarted). - * No way to erase old effects managed by ff-core and need reboot. - */ - bool isCreated = (mFfEffects[targetId].id != -1); - if (isCreated && ioctl(mInputFd, EVIOCRMFF, targetId) < 0) { - ALOGW("Failed to erase effect %d(%d) (%d): %s", targetId, mFfEffects[targetId].id, errno, - strerror(errno)); - mFfEffects[targetId].id = targetId; - - /* Edit the current effect to see if we can make effect lists aligned. */ - if (ioctl(mInputFd, EVIOCSFF, &mFfEffects[targetId]) < 0) { - /* If it is EINVAL 22 Invalid argument, the owner is not the current HAL instance. */ - ALOGE("Failed to upload effect %d (%d): %s", targetId, errno, strerror(errno)); - delete[](mFfEffects[targetId].u.periodic.custom_data); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); - } else { - ALOGV("Successful to overwrite effect %d.", targetId); + if (mFfEffects[targetId].id != -1) { + ALOGE("mFfEffects[targetId].id != -1"); + } + + /* Create a new OWT waveform to update the PWLE or composite effect. */ + mFfEffects[targetId].id = -1; + if (ioctl(mInputFd, EVIOCSFF, &mFfEffects[targetId]) < 0) { + ALOGE("Failed to upload effect %d (%d): %s", targetId, errno, strerror(errno)); + delete[](mFfEffects[targetId].u.periodic.custom_data); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + + if (mFfEffects[targetId].id >= FF_MAX_EFFECTS || mFfEffects[targetId].id < 0) { + ALOGE("Invalid waveform index after upload OWT effect: %d", mFfEffects[targetId].id); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + *outEffectIndex = mFfEffects[targetId].id; + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::eraseOwtEffect(int8_t effectIndex) { + uint32_t effectCountBefore, effectCountAfter, i, successFlush = 0; + + if (effectIndex < WAVEFORM_MAX_PHYSICAL_INDEX) { + ALOGE("Invalid waveform index for OWT erase: %d", effectIndex); + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + if (effectIndex < WAVEFORM_MAX_INDEX) { + /* Normal situation. Only erase the effect which we just played. */ + if (ioctl(mInputFd, EVIOCRMFF, effectIndex) < 0) { + ALOGE("Failed to erase effect %d (%d): %s", effectIndex, errno, strerror(errno)); + } + for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < WAVEFORM_MAX_INDEX; i++) { + if (mFfEffects[i].id == effectIndex) { + mFfEffects[i].id = -1; + break; + } } } else { - /* Create a new OWT waveform to update the PWLE or composite effect. */ - mFfEffects[targetId].id = -1; - if (ioctl(mInputFd, EVIOCSFF, &mFfEffects[targetId]) < 0) { - ALOGE("Failed to upload effect %d (%d): %s", targetId, errno, strerror(errno)); - delete[](mFfEffects[targetId].u.periodic.custom_data); - return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + /* Flush all non-prestored effects of ff-core and driver. */ + mHwApi->getEffectCount(&effectCountBefore); + for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < FF_MAX_EFFECTS; i++) { + if (ioctl(mInputFd, EVIOCRMFF, i) >= 0) { + successFlush++; + } + } + mHwApi->getEffectCount(&effectCountAfter); + ALOGW("Flushed effects: ff: %d; driver: %d -> %d; success: %d", effectIndex, + effectCountBefore, effectCountAfter, successFlush); + /* Reset all OWT effect index of HAL. */ + for (i = WAVEFORM_MAX_PHYSICAL_INDEX; i < WAVEFORM_MAX_INDEX; i++) { + mFfEffects[i].id = -1; } } - *outEffectIndex = mFfEffects[targetId].id; - return ndk::ScopedAStatus::ok(); } @@ -1398,6 +1414,7 @@ ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strengt ch = dspmem_chunk_create(new uint8_t[FF_CUSTOM_DATA_LEN_MAX_COMP]{0x00}, FF_CUSTOM_DATA_LEN_MAX_COMP); status = getCompoundDetails(effect, strength, &timeMs, ch); + volLevel = VOLTAGE_SCALE_MAX; break; default: status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); @@ -1407,7 +1424,7 @@ ndk::ScopedAStatus Vibrator::performEffect(Effect effect, EffectStrength strengt goto exit; } - status = performEffect(static_cast<uint16_t>(effectIndex), volLevel, ch, callback); + status = performEffect(effectIndex, volLevel, ch, callback); exit: *outTimeMs = timeMs; @@ -1417,26 +1434,22 @@ exit: ndk::ScopedAStatus Vibrator::performEffect(uint32_t effectIndex, uint32_t volLevel, dspmem_chunk *ch, const std::shared_ptr<IVibratorCallback> &callback) { - if (ch) { - ndk::ScopedAStatus status = uploadOwtEffect(ch->head, dspmem_chunk_bytes(ch), &effectIndex); - delete ch; - if (!status.isOk()) { - return status; - } - setEffectAmplitude(VOLTAGE_SCALE_MAX, VOLTAGE_SCALE_MAX); - } else { - setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX); - } + setEffectAmplitude(volLevel, VOLTAGE_SCALE_MAX); - return on(MAX_TIME_MS, effectIndex, callback); + return on(MAX_TIME_MS, effectIndex, ch, callback); } void Vibrator::waitForComplete(std::shared_ptr<IVibratorCallback> &&callback) { if (!mHwApi->pollVibeState(VIBE_STATE_HAPTIC, POLLING_TIMEOUT)) { - ALOGE("Fail to get state \"Haptic\""); + ALOGW("Failed to get state \"Haptic\""); } mHwApi->pollVibeState(VIBE_STATE_STOPPED); + if (mActiveId >= WAVEFORM_MAX_PHYSICAL_INDEX) { + eraseOwtEffect(mActiveId); + } + mActiveId = -1; + if (callback) { auto ret = callback->onComplete(); if (!ret.isOk()) { diff --git a/vibrator/cs40l26/Vibrator.h b/vibrator/cs40l26/Vibrator.h index a183cac0..4647725a 100644 --- a/vibrator/cs40l26/Vibrator.h +++ b/vibrator/cs40l26/Vibrator.h @@ -17,6 +17,7 @@ #include <aidl/android/hardware/vibrator/BnVibrator.h> #include <android-base/unique_fd.h> +#include <linux/input.h> #include <tinyalsa/asoundlib.h> #include <array> @@ -131,7 +132,7 @@ class Vibrator : public BnVibrator { binder_status_t dump(int fd, const char **args, uint32_t numArgs) override; private: - ndk::ScopedAStatus on(uint32_t timeoutMs, uint32_t effectIndex, + ndk::ScopedAStatus on(uint32_t timeoutMs, uint32_t effectIndex, struct dspmem_chunk *ch, const std::shared_ptr<IVibratorCallback> &callback); // set 'amplitude' based on an arbitrary scale determined by 'maximum' ndk::ScopedAStatus setEffectAmplitude(float amplitude, float maximum); @@ -146,6 +147,7 @@ class Vibrator : public BnVibrator { ndk::ScopedAStatus getPrimitiveDetails(CompositePrimitive primitive, uint32_t *outEffectIndex); ndk::ScopedAStatus uploadOwtEffect(uint8_t *owtData, uint32_t num_bytes, uint32_t *outEffectIndex); + ndk::ScopedAStatus eraseOwtEffect(int8_t effectIndex); ndk::ScopedAStatus performEffect(Effect effect, EffectStrength strength, const std::shared_ptr<IVibratorCallback> &callback, int32_t *outTimeMs); @@ -166,6 +168,7 @@ class Vibrator : public BnVibrator { std::array<uint32_t, 2> mTickEffectVol; std::array<uint32_t, 2> mClickEffectVol; std::array<uint32_t, 2> mLongEffectVol; + std::vector<ff_effect> mFfEffects; std::vector<uint32_t> mEffectDurations; std::future<void> mAsyncHandle; ::android::base::unique_fd mInputFd; diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual.rc b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual.rc index 5e8aac7f..cd47c3a0 100644 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual.rc +++ b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual.rc @@ -1,4 +1,4 @@ -on boot && property:vendor.all.modules.ready=1 +on enable-thermal-hal wait /sys/bus/i2c/devices/i2c-cs40l26a-dual/calibration/redc_cal_time_ms mkdir /mnt/vendor/persist/haptics 0770 system system diff --git a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26.rc b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26.rc index 89d0eb7f..c2b9e635 100644 --- a/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26.rc +++ b/vibrator/cs40l26/android.hardware.vibrator-service.cs40l26.rc @@ -1,4 +1,4 @@ -on boot && property:vendor.all.modules.ready=1 +on enable-thermal-hal wait /sys/bus/i2c/devices/i2c-cs40l26a/calibration/redc_cal_time_ms mkdir /mnt/vendor/persist/haptics 0770 system system |