Merge "Use epoll to monitor sysfs in carpowerpolicyd" into sc-v2-dev
diff --git a/cpp/libsysfsmonitor/Android.bp b/cpp/libsysfsmonitor/Android.bp
new file mode 100644
index 0000000..545255b
--- /dev/null
+++ b/cpp/libsysfsmonitor/Android.bp
@@ -0,0 +1,60 @@
+// Copyright (C) 2021 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_defaults {
+    name: "libsysfsmonitor_defaults",
+    cflags: [
+        "-Wall",
+        "-Wno-missing-field-initializers",
+        "-Werror",
+        "-Wno-unused-variable",
+        "-Wunused-parameter",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libutils",
+    ],
+}
+
+cc_library {
+    name: "libsysfsmonitor",
+    srcs: [
+        "src/SysfsMonitor.cpp",
+    ],
+    defaults: [
+        "libsysfsmonitor_defaults",
+    ],
+    export_include_dirs: [
+        "src",
+    ],
+}
+
+cc_test {
+    name: "libsysfsmonitor_test",
+    srcs: [
+        "tests/SysfsMonitorTest.cpp",
+    ],
+    defaults: [
+        "libsysfsmonitor_defaults",
+    ],
+    static_libs: [
+        "libgtest",
+        "libsysfsmonitor",
+    ],
+}
diff --git a/cpp/libsysfsmonitor/src/SysfsMonitor.cpp b/cpp/libsysfsmonitor/src/SysfsMonitor.cpp
new file mode 100644
index 0000000..ee89ec0
--- /dev/null
+++ b/cpp/libsysfsmonitor/src/SysfsMonitor.cpp
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2021, 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 "libsysfsmonitor"
+#define DEBUG false
+
+#include "SysfsMonitor.h"
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+
+#include <sys/epoll.h>
+
+namespace {
+
+using ::android::base::Error;
+using ::android::base::Result;
+using ::android::base::StringPrintf;
+
+// The maximum number of sysfs files to monitor.
+constexpr int32_t EPOLL_MAX_EVENTS = 10;
+
+}  // namespace
+
+namespace android {
+namespace automotive {
+
+Result<void> SysfsMonitor::init(CallbackFunc callback) {
+    if (mEpollFd >= 0) {
+        return Error() << "Epoll instance was already created";
+    }
+    if (mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC)); mEpollFd < 0) {
+        return Error() << "Cannot create epoll instance: errno = " << errno;
+    }
+    mCallback = callback;
+    return {};
+}
+
+Result<void> SysfsMonitor::release() {
+    if (mEpollFd < 0) {
+        return Error() << "Epoll instance wasn't created";
+    }
+    for (const int32_t fd : mMonitoringFds) {
+        if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, /*event=*/nullptr)) {
+            ALOGW("Failed to deregister fd(%d) from epoll instance: errno = %d", fd, errno);
+        }
+    }
+    mMonitoringFds.clear();
+    mEpollFd.reset();
+    mCallback = nullptr;
+    return {};
+}
+
+Result<void> SysfsMonitor::registerFd(int32_t fd) {
+    if (fd < 0) {
+        return Error() << StringPrintf("fd(%d) is invalid", fd);
+    }
+    if (mMonitoringFds.count(fd) > 0) {
+        return Error() << StringPrintf("fd(%d) is already being monitored", fd);
+    }
+    if (mMonitoringFds.size() == EPOLL_MAX_EVENTS) {
+        return Error() << "Cannot monitor more than " << EPOLL_MAX_EVENTS << " sysfs files";
+    }
+    struct epoll_event eventItem = {};
+    eventItem.events = EPOLLIN | EPOLLPRI | EPOLLET;
+    eventItem.data.fd = fd;
+    if (int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem); result != 0) {
+        return Error() << StringPrintf("Failed to add fd(%d) to epoll instance: errno = %d", fd,
+                                       errno);
+    }
+    mMonitoringFds.insert(fd);
+    return {};
+}
+
+Result<void> SysfsMonitor::unregisterFd(int32_t fd) {
+    if (fd < 0) {
+        return Error() << StringPrintf("fd(%d) is invalid", fd);
+    }
+    if (mMonitoringFds.count(fd) == 0) {
+        return Error() << StringPrintf("fd(%d) is not being monitored", fd);
+    }
+    // Even when epoll_ctl() fails, we proceed to handle the request.
+    if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, /*event=*/nullptr)) {
+        ALOGW("Failed to deregister fd(%d) from epoll instance: errno = %d", fd, errno);
+    }
+    mMonitoringFds.erase(fd);
+    return {};
+}
+
+Result<void> SysfsMonitor::observe() {
+    if (mEpollFd < 0) {
+        return Error() << "Epoll instance is not initialized";
+    }
+
+    struct epoll_event events[EPOLL_MAX_EVENTS];
+    while (true) {
+        int pollResult = epoll_wait(mEpollFd, events, EPOLL_MAX_EVENTS, /*timeout=*/-1);
+        if (pollResult < 0) {
+            ALOGW("Polling sysfs failed, but continue polling: errno = %d", errno);
+            continue;
+        }
+        std::vector<int32_t> fds;
+        for (int i = 0; i < pollResult; i++) {
+            int fd = events[i].data.fd;
+            if (mMonitoringFds.count(fd) == 0) {
+                continue;
+            }
+            if (events[i].events & EPOLLIN) {
+                fds.push_back(fd);
+            } else if (events[i].events & EPOLLERR) {
+                ALOGW("An error occurred when polling fd(%d)", fd);
+            }
+        }
+        if (mCallback && fds.size() > 0) {
+            mCallback(fds);
+        }
+    }
+    return {};
+}
+
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/libsysfsmonitor/src/SysfsMonitor.h b/cpp/libsysfsmonitor/src/SysfsMonitor.h
new file mode 100644
index 0000000..f941041
--- /dev/null
+++ b/cpp/libsysfsmonitor/src/SysfsMonitor.h
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2021, 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 CPP_LIBSYSFSMONITOR_SRC_SYSFSMONITOR_H_
+#define CPP_LIBSYSFSMONITOR_SRC_SYSFSMONITOR_H_
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <utils/RefBase.h>
+
+#include <functional>
+#include <string>
+#include <unordered_set>
+
+namespace android {
+namespace automotive {
+
+using CallbackFunc = ::std::function<void(const std::vector<int32_t>&)>;
+
+/**
+ * SysfsMonitor monitors sysfs file changes and invokes the registered callback when there is a
+ * change at the sysfs files to monitor.
+ */
+class SysfsMonitor final : public RefBase {
+public:
+    // Initializes SysfsMonitor instance.
+    android::base::Result<void> init(CallbackFunc callback);
+    // Releases resources used for monitoring.
+    android::base::Result<void> release();
+    // Registers a sysfs file to monitor.
+    android::base::Result<void> registerFd(int32_t fd);
+    // Unregisters a sysfs file to monitor.
+    android::base::Result<void> unregisterFd(int32_t fd);
+    // Starts observing sysfs file changes.
+    android::base::Result<void> observe();
+
+private:
+    android::base::unique_fd mEpollFd;
+    std::unordered_set<int32_t> mMonitoringFds;
+    CallbackFunc mCallback;
+};
+
+}  // namespace automotive
+}  // namespace android
+
+#endif  // CPP_LIBSYSFSMONITOR_SRC_SYSFSMONITOR_H_
diff --git a/cpp/libsysfsmonitor/tests/SysfsMonitorTest.cpp b/cpp/libsysfsmonitor/tests/SysfsMonitorTest.cpp
new file mode 100644
index 0000000..f6dda6c
--- /dev/null
+++ b/cpp/libsysfsmonitor/tests/SysfsMonitorTest.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2021, 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 "SysfsMonitor.h"
+
+#include <gtest/gtest.h>
+#include <utils/StrongPointer.h>
+
+#include <sys/socket.h>
+
+#include <vector>
+
+namespace android {
+namespace automotive {
+
+class SysfsMonitorTest : public ::testing::Test {
+public:
+    void SetUp() override { mSysfsMonitor = sp<SysfsMonitor>::make(); }
+    void TearDown() override { mSysfsMonitor = nullptr; }
+
+protected:
+    sp<SysfsMonitor> mSysfsMonitor;
+};
+
+TEST_F(SysfsMonitorTest, TestDuplicateInitialize) {
+    auto ret = mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+    ASSERT_TRUE(ret.ok()) << "First initialization should be successful: " << ret.error().message();
+    ASSERT_FALSE(mSysfsMonitor->init([](const std::vector<int32_t>&) {}).ok())
+            << "Initialization cannot be done twice";
+}
+
+TEST_F(SysfsMonitorTest, TestDuplicateRelease) {
+    auto ret = mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+    ASSERT_TRUE(ret.ok()) << "First initialization should be successful: " << ret.error().message();
+    ret = mSysfsMonitor->release();
+    ASSERT_TRUE(ret.ok()) << "Releasing the initialized instance should be successful: "
+                          << ret.error().message();
+    ASSERT_FALSE(mSysfsMonitor->release().ok()) << "Released instance cannot be released";
+}
+
+TEST_F(SysfsMonitorTest, TestNoInitRelease) {
+    ASSERT_FALSE(mSysfsMonitor->release().ok()) << "Uninitailized instance cannot be released";
+}
+
+TEST_F(SysfsMonitorTest, TestUnregisterNotRegisteredFd) {
+    // A regular file cannot be registered to epoll instance. So, the test is using a socket file.
+    int32_t fd = socket(AF_UNIX, SOCK_DGRAM, /*protocol=*/0);
+    mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+
+    ASSERT_FALSE(mSysfsMonitor->unregisterFd(fd).ok())
+            << "Unregistered file description cannot be unregistered";
+    close(fd);
+}
+
+TEST_F(SysfsMonitorTest, TestDuplicateRegister) {
+    int32_t fd = socket(AF_UNIX, SOCK_DGRAM, /*protocol=*/0);
+    mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+
+    auto ret = mSysfsMonitor->registerFd(fd);
+    ASSERT_TRUE(ret.ok()) << "Registering a file descriptor first time should be successful: "
+                          << ret.error().message();
+    ASSERT_FALSE(mSysfsMonitor->registerFd(fd).ok())
+            << "Registering a file descriptor twice cannot be done";
+    close(fd);
+}
+
+TEST_F(SysfsMonitorTest, TestDuplicateUnregister) {
+    int32_t fd = socket(AF_UNIX, SOCK_DGRAM, /*protocol=*/0);
+    mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+
+    auto ret = mSysfsMonitor->registerFd(fd);
+    ASSERT_TRUE(ret.ok()) << "Registering a file descriptor first time should be successful: "
+                          << ret.error().message();
+    ret = mSysfsMonitor->unregisterFd(fd);
+    ASSERT_TRUE(ret.ok()) << "The registered file descriptor should be unregistered: "
+                          << ret.error().message();
+    ASSERT_FALSE(mSysfsMonitor->unregisterFd(fd).ok())
+            << "Unregistering the unregistered file descriptor cannot be done";
+    close(fd);
+}
+
+TEST_F(SysfsMonitorTest, TestRegisterInvalidFd) {
+    const int32_t invalidFd = -1;
+    ASSERT_FALSE(mSysfsMonitor->registerFd(invalidFd).ok())
+            << "fd(-1) cannot be registered to SysfsMonitor";
+}
+
+TEST_F(SysfsMonitorTest, TestUnregisterInvalidFd) {
+    const int32_t invalidFd = -1;
+    ASSERT_FALSE(mSysfsMonitor->unregisterFd(invalidFd).ok())
+            << "fd(-1) cannot be given to unregisterFd";
+}
+
+TEST_F(SysfsMonitorTest, TestRegisterMultipleFds) {
+    const int32_t maxFdCount = 10;
+    int32_t fdsToMonitor[maxFdCount + 1];
+
+    mSysfsMonitor->init([](const std::vector<int32_t>&) {});
+    for (int i = 0; i < maxFdCount; i++) {
+        fdsToMonitor[i] = socket(AF_UNIX, SOCK_DGRAM, /*protocol=*/0);
+        auto ret = mSysfsMonitor->registerFd(fdsToMonitor[i]);
+        ASSERT_TRUE(ret.ok()) << "Registering a file descriptor first time should be successful: "
+                              << ret.error().message();
+    }
+    fdsToMonitor[maxFdCount] = socket(AF_UNIX, SOCK_DGRAM, /*protocol=*/0);
+    ASSERT_FALSE(mSysfsMonitor->registerFd(fdsToMonitor[maxFdCount]).ok())
+            << "Registering more than " << maxFdCount << " files cannot be done";
+
+    mSysfsMonitor->release();
+    for (int i = 0; i <= maxFdCount; i++) {
+        close(fdsToMonitor[i]);
+    }
+}
+
+TEST_F(SysfsMonitorTest, TestObserveWithoutInitialization) {
+    ASSERT_FALSE(mSysfsMonitor->observe().ok()) << "Uninitialized instance cannot observe";
+}
+
+}  // namespace automotive
+}  // namespace android
diff --git a/cpp/powerpolicy/server/Android.bp b/cpp/powerpolicy/server/Android.bp
index 094a3f5..2c4a9fa 100644
--- a/cpp/powerpolicy/server/Android.bp
+++ b/cpp/powerpolicy/server/Android.bp
@@ -33,6 +33,7 @@
         "libbinder",
         "libhidlbase",
         "liblog",
+        "libsysfsmonitor",
         "libtinyxml2",
         "libutils",
     ],
diff --git a/cpp/powerpolicy/server/src/SilentModeHandler.cpp b/cpp/powerpolicy/server/src/SilentModeHandler.cpp
index c57b6fa..79d78be 100644
--- a/cpp/powerpolicy/server/src/SilentModeHandler.cpp
+++ b/cpp/powerpolicy/server/src/SilentModeHandler.cpp
@@ -25,7 +25,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
-#include <sys/inotify.h>
+#include <sys/epoll.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
@@ -35,6 +35,7 @@
 namespace powerpolicy {
 
 using ::android::Mutex;
+using ::android::automotive::SysfsMonitor;
 using ::android::base::Error;
 using ::android::base::GetProperty;
 using ::android::base::ReadFileToString;
@@ -49,12 +50,11 @@
 
 constexpr const char kPropertySystemBootReason[] = "sys.boot.reason";
 constexpr const char kSilentModeHwStateFilename[] = "/sys/power/pm_silentmode_hw_state";
-constexpr const char kKernelSilentModeFilename[] = "/sys/power/pm_silentmode_kernel";
+constexpr const char kKernelSilentModeFilename[] = "/sys/power/pm_silentmode_kernel_state";
 // To prevent boot animation from being started.
 constexpr const char kPropertyNoBootAnimation[] = "debug.sf.nobootanimation";
 // To stop boot animation while it is being played.
 constexpr const char kPropertyBootAnimationExit[] = "service.bootanim.exit";
-constexpr int kEventBufferSize = 512;
 
 bool fileExists(const char* filename) {
     struct stat buffer;
@@ -68,7 +68,7 @@
       mSilentModeHwStateFilename(kSilentModeHwStateFilename),
       mKernelSilentModeFilename(kKernelSilentModeFilename),
       mSilentModeChangeHandler(handler),
-      mFdInotify(-1) {
+      mSysfsMonitor(sp<SysfsMonitor>::make()) {
     mBootReason = GetProperty(kPropertySystemBootReason, "");
 }
 
@@ -83,7 +83,7 @@
     if (mForcedMode) {
         handleSilentModeChange(mSilentModeByHwState);
         mSilentModeChangeHandler->notifySilentModeChange(mSilentModeByHwState);
-        ALOGI("Now in forced mode: monitoring %s is disabled", kSilentModeHwStateFilename);
+        ALOGI("Now in forced mode: monitoring %s is disabled", mSilentModeHwStateFilename.c_str());
     } else {
         startMonitoringSilentModeHwState();
     }
@@ -101,13 +101,15 @@
 void SilentModeHandler::stopMonitoringSilentModeHwState(bool shouldWaitThread) {
     if (mIsMonitoring) {
         mIsMonitoring = false;
-        inotify_rm_watch(mFdInotify, mWdSilentModeHwState);
-        mWdSilentModeHwState = -1;
+        if (auto ret = mSysfsMonitor->unregisterFd(mFdSilentModeHwState.get()); !ret.ok()) {
+            ALOGW("Unregistering %s from SysfsMonitor failed", mSilentModeHwStateFilename.c_str());
+        }
         if (shouldWaitThread && mSilentModeMonitoringThread.joinable()) {
             mSilentModeMonitoringThread.join();
         }
     }
-    mFdInotify.reset(-1);
+    mFdSilentModeHwState.reset();
+    mSysfsMonitor->release();
 }
 
 Result<void> SilentModeHandler::dump(int fd, const Vector<String16>& /*args*/) {
@@ -132,56 +134,38 @@
         ALOGW("Silent Mode monitoring is already started");
         return;
     }
-    if (mFdInotify < 0) {
-        mFdInotify.reset(inotify_init1(IN_CLOEXEC));
-        if (mFdInotify < 0) {
-            ALOGE("Failed to start monitoring Silent Mode HW state: creating inotify instance "
-                  "failed (errno = %d)",
-                  errno);
-            return;
-        }
-    }
     const char* filename = mSilentModeHwStateFilename.c_str();
     if (!fileExists(filename)) {
         ALOGW("Failed to start monitoring Silent Mode HW state: %s doesn't exist", filename);
-        mFdInotify.reset(-1);
         return;
     }
-    // TODO(b/178843534): Additional masks might be needed to detect sysfs change.
-    const uint32_t masks = IN_MODIFY;
-    mWdSilentModeHwState = inotify_add_watch(mFdInotify, filename, masks);
+    if (mFdSilentModeHwState == -1) {
+        if (mFdSilentModeHwState.reset(open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
+            mFdSilentModeHwState == -1) {
+            ALOGW("Failed to open %s for monitoring: errno = %d", filename, errno);
+            return;
+        }
+    }
+    auto ret = mSysfsMonitor->init([this](const std::vector<int32_t>& fileDescriptors) {
+        // Only one sysfs file is registered.
+        if (mFdSilentModeHwState != fileDescriptors[0]) {
+            return;
+        }
+        handleSilentModeHwStateChange();
+    });
+    if (!ret.ok()) {
+        ALOGW("Failed to initialize SysfsMonitor: %s", ret.error().message().c_str());
+        return;
+    }
+    if (auto ret = mSysfsMonitor->registerFd(mFdSilentModeHwState.get()); !ret.ok()) {
+        ALOGW("Failed to register %s to SysfsMonitor: %s", filename, ret.error().message().c_str());
+        return;
+    }
     mIsMonitoring = true;
-    mSilentModeMonitoringThread = std::thread([this]() {
-        char eventBuf[kEventBufferSize];
-        struct inotify_event* event;
-        constexpr size_t inotifyEventSize = sizeof(*event);
-        ALOGI("Monitoring %s started", mSilentModeHwStateFilename.c_str());
-        while (mIsMonitoring) {
-            int eventPos = 0;
-            int numBytes = read(mFdInotify, eventBuf, sizeof(eventBuf));
-            if (numBytes < static_cast<int>(inotifyEventSize)) {
-                if (errno == EINTR) {
-                    ALOGW("System call interrupted. Wait for inotify event again.");
-                    continue;
-                }
-                mIsMonitoring = false;
-                inotify_rm_watch(mFdInotify, mWdSilentModeHwState);
-                mWdSilentModeHwState = -1;
-                mFdInotify.reset(-1);
-                ALOGW("Failed to wait for change at %s (errno = %d)",
-                      mSilentModeHwStateFilename.c_str(), errno);
-                return;
-            }
-            while (numBytes >= static_cast<int>(inotifyEventSize)) {
-                int eventSize;
-                event = (struct inotify_event*)(eventBuf + eventPos);
-                if (event->wd == mWdSilentModeHwState && (event->mask & masks)) {
-                    handleSilentModeHwStateChange();
-                }
-                eventSize = inotifyEventSize + event->len;
-                numBytes -= eventSize;
-                eventPos += eventSize;
-            }
+    mSilentModeMonitoringThread = std::thread([this, filename]() {
+        if (auto ret = mSysfsMonitor->observe(); !ret.ok()) {
+            ALOGI("Failed to observe %s", filename);
+            return;
         }
         ALOGI("Monitoring %s ended", mSilentModeHwStateFilename.c_str());
     });
diff --git a/cpp/powerpolicy/server/src/SilentModeHandler.h b/cpp/powerpolicy/server/src/SilentModeHandler.h
index 9fae109..96074f8 100644
--- a/cpp/powerpolicy/server/src/SilentModeHandler.h
+++ b/cpp/powerpolicy/server/src/SilentModeHandler.h
@@ -21,8 +21,11 @@
 #include <android-base/unique_fd.h>
 #include <utils/Mutex.h>
 #include <utils/String16.h>
+#include <utils/StrongPointer.h>
 #include <utils/Vector.h>
 
+#include <SysfsMonitor.h>
+
 #include <atomic>
 #include <thread>  // NOLINT(build/c++11)
 
@@ -47,8 +50,8 @@
 
 /**
  * SilentModeHandler monitors {@code /sys/power/pm_silentmode_hw_state} in sysfs to detect Silent
- * Mode change by a vehicle processor. Also, it updates {@code /sys/power/pm_silentmode_kernel} in
- * sysfs to tell kernel the current Silent Mode.
+ * Mode change by a vehicle processor. Also, it updates
+ * {@code /sys/power/pm_silentmode_kernel_state} in sysfs to tell kernel the current Silent Mode.
  */
 class SilentModeHandler final {
 public:
@@ -80,9 +83,9 @@
     std::string mKernelSilentModeFilename;
     ISilentModeChangeHandler* mSilentModeChangeHandler;
     std::thread mSilentModeMonitoringThread;
-    android::base::unique_fd mFdInotify;
-    int mWdSilentModeHwState = -1;
     std::atomic_bool mIsMonitoring = false;
+    android::sp<android::automotive::SysfsMonitor> mSysfsMonitor;
+    android::base::unique_fd mFdSilentModeHwState;
 
     // For unit tests.
     friend class internal::SilentModeHandlerPeer;
diff --git a/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp b/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp
index 1eaec81..6548cf1 100644
--- a/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp
+++ b/cpp/powerpolicy/server/tests/SilentModeHandlerTest.cpp
@@ -46,20 +46,6 @@
 constexpr int kMaxPollingAttempts = 5;
 constexpr std::chrono::microseconds kPollingDelayUs = 50ms;
 
-bool waitForSilentMode(SilentModeHandler* handler, bool expectedSilentMode) {
-    int count = 0;
-    while (true) {
-        if (handler->isSilentMode() == expectedSilentMode) {
-            return true;
-        }
-        if (count++; count == kMaxPollingAttempts) {
-            break;
-        }
-        usleep(kPollingDelayUs.count());
-    }
-    return false;
-}
-
 }  // namespace
 
 namespace internal {
@@ -124,23 +110,6 @@
     sp<MockCarPowerPolicyServer> carPowerPolicyServer;
 };
 
-TEST_F(SilentModeHandlerTest, TestSilentModeHwStateMonitoring) {
-    SilentModeHandler handler(carPowerPolicyServer.get());
-    internal::SilentModeHandlerPeer handlerPeer(&handler);
-    handlerPeer.injectBootReason(kBootReasonNormal);
-    handlerPeer.init();
-
-    handlerPeer.updateSilentModeHwState(/*isSilent=*/true);
-
-    ASSERT_TRUE(waitForSilentMode(&handler, /*expectedSilentMode=*/true))
-            << "It should be silent mode when HW state is on";
-
-    handlerPeer.updateSilentModeHwState(/*isSilent=*/false);
-
-    ASSERT_TRUE(waitForSilentMode(&handler, /*expectedSilentMode=*/false))
-            << "It should be non-silent mode when HW state is off";
-}
-
 TEST_F(SilentModeHandlerTest, TestRebootForForcedSilentMode) {
     SilentModeHandler handler(carPowerPolicyServer.get());
     internal::SilentModeHandlerPeer handlerPeer(&handler);
diff --git a/service/src/com/android/car/power/SilentModeHandler.java b/service/src/com/android/car/power/SilentModeHandler.java
index 2631c01..bb78810 100644
--- a/service/src/com/android/car/power/SilentModeHandler.java
+++ b/service/src/com/android/car/power/SilentModeHandler.java
@@ -39,9 +39,9 @@
  * Class to handle Silent Mode and Non-Silent Mode.
  *
  * <p>This monitors {@code /sys/power/pm_silentmode_hw_state} to figure out when to switch to Silent
- * Mode and updates {@code /sys/power/pm_silentmode_kernel} to tell early-init services about Silent
- * Mode change. Also, it handles forced Silent Mode for testing purpose, which is given through
- * reboot reason.
+ * Mode and updates {@code /sys/power/pm_silentmode_kernel_state} to tell early-init services about
+ * Silent Mode change. Also, it handles forced Silent Mode for testing purpose, which is given
+ * through reboot reason.
  */
 final class SilentModeHandler {
     static final String SILENT_MODE_FORCED_SILENT = "forced-silent";
@@ -53,7 +53,7 @@
     private static final String SYSFS_FILENAME_HW_STATE_MONITORING =
             "/sys/power/pm_silentmode_hw_state";
     private static final String SYSFS_FILENAME_KERNEL_SILENTMODE =
-            "/sys/power/pm_silentmode_kernel";
+            "/sys/power/pm_silentmode_kernel_state";
     private static final String VALUE_SILENT_MODE = "1";
     private static final String VALUE_NON_SILENT_MODE = "0";
     private static final String SYSTEM_BOOT_REASON = "sys.boot.reason";