summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-10-19 03:44:51 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-10-19 03:44:51 +0000
commitc2332b1acc1eb3efd4ae364b2c8e41d200d1fffc (patch)
tree4a14e034e636acc64ad4f7ca306bd747115d0a34
parentc3f45dc3f123b615c1328c8c7b488d06ae6943c7 (diff)
parentdad6bbcb3ff7e96e479958636b29d15e2591d831 (diff)
downloadpixel-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.bp47
-rw-r--r--battery_mitigation/BatteryMitigation.cpp32
-rw-r--r--battery_mitigation/MitigationThermalManager.cpp187
-rw-r--r--battery_mitigation/OWNERS2
-rw-r--r--battery_mitigation/include/battery_mitigation/BatteryMitigation.h39
-rw-r--r--battery_mitigation/include/battery_mitigation/MitigationConfig.h48
-rw-r--r--battery_mitigation/include/battery_mitigation/MitigationThermalManager.h125
-rw-r--r--fastboot/Fastboot.cpp49
-rw-r--r--power-libperfmgr/aidl/PowerHintSession.cpp12
-rw-r--r--powerstats/android.hardware.power.stats-service.pixel.rc14
-rw-r--r--vibrator/cs40l26/Vibrator.cpp239
-rw-r--r--vibrator/cs40l26/Vibrator.h5
-rw-r--r--vibrator/cs40l26/android.hardware.vibrator-service.cs40l26-dual.rc2
-rw-r--r--vibrator/cs40l26/android.hardware.vibrator-service.cs40l26.rc2
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