Snap for 13832108 from e5ffa0c08242d396705f0c9ddb7caa175da2d11a to 25Q4-release

Change-Id: I6ac3609ea9cb6695ba025f913afe808717f90dca
diff --git a/test_kill_secureelement/Android.bp b/test_kill_secureelement/Android.bp
new file mode 100644
index 0000000..f04b050
--- /dev/null
+++ b/test_kill_secureelement/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2025 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_test {
+    name: "weaver_kill_secureelement_test",
+    team: "trendy_team_pixel_watch_system_software",
+    srcs: ["weaver_kill_secureelement_test.cpp"],
+
+    shared_libs: [
+        "libbase",
+        "libutils",
+        "libbinder_ndk",
+        "android.hardware.weaver-V2-ndk",
+    ],
+    require_root: true,
+}
diff --git a/test_kill_secureelement/weaver_kill_secureelement_test.cpp b/test_kill_secureelement/weaver_kill_secureelement_test.cpp
new file mode 100644
index 0000000..c2d2aa9
--- /dev/null
+++ b/test_kill_secureelement/weaver_kill_secureelement_test.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2025 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 <gtest/gtest.h>
+
+#include <aidl/android/hardware/weaver/IWeaver.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <chrono>
+#include <csignal>
+#include <future>
+#include <string>
+#include <thread>
+
+using aidl::android::hardware::weaver::IWeaver;
+using aidl::android::hardware::weaver::WeaverConfig;
+
+constexpr char SECURE_ELEMENT_SERVICE_NAME[]
+                                = "android.se.omapi.ISecureElementService/default";
+constexpr char WEAVER_SERVICE_NAME[] = "android.hardware.weaver.IWeaver/default";
+
+// Helper function to run a command and capture its standard output.
+// Returns true on success (exit code 0), false otherwise.
+static bool RunCommand(const std::string& command, std::string& stdout_str) {
+    stdout_str.clear();
+    FILE* pipe = popen(command.c_str(), "r");
+    if (!pipe) {
+        PLOG(ERROR) << "Failed to popen command: " << command;
+        return false;
+    }
+
+    if (!android::base::ReadFdToString(fileno(pipe), &stdout_str)) {
+        LOG(ERROR) << "Failed to read command output.";
+        return false;
+    }
+
+    int status = pclose(pipe);
+    return WIFEXITED(status) && WEXITSTATUS(status) == 0;
+}
+
+// Gets the PID of the Secure Element service using dumpsys.
+// Returns the PID as an integer, or <=0 if the service is not running or on error.
+static int GetSecureElementServicePid() {
+    std::string pid_str;
+    const std::string command = "dumpsys --pid " + std::string(SECURE_ELEMENT_SERVICE_NAME);
+    if (RunCommand(command, pid_str)) {
+        pid_str.erase(pid_str.find_last_not_of(" \n\r\t") + 1);
+        if (!pid_str.empty() && std::all_of(pid_str.begin(), pid_str.end(), ::isdigit)) {
+            return atoi(pid_str.c_str());
+        }
+    }
+    return -1;
+}
+
+// Verifies that the Weaver HAL is responsive by calling its getConfig method.
+// Returns an AssertionResult to indicate success or failure.
+testing::AssertionResult CheckWeaverHalIsResponding() {
+    LOG(INFO) << "Checking if Weaver HAL is responding..";
+    ndk::SpAIBinder binder(AServiceManager_waitForService(WEAVER_SERVICE_NAME));
+    std::shared_ptr<IWeaver> weaver_service = IWeaver::fromBinder(binder);
+    if (weaver_service == nullptr) {
+        return testing::AssertionFailure() << "Failed to get Weaver AIDL service.";
+    }
+
+    WeaverConfig config;
+    ndk::ScopedAStatus status = weaver_service->getConfig(&config);
+    if (!status.isOk()) {
+        return testing::AssertionFailure()
+                    << "Weaver HAL's getConfig() returned an error: "
+                    << status.getMessage();
+    }
+    LOG(INFO) << "Weaver HAL is responding without errors.";
+    return testing::AssertionSuccess();
+}
+
+static void OnBinderDied(void* promise_cookie) {
+    LOG(INFO) << "Received a binder died notification for the service.";
+    // Set the promise the test is waiting on.
+    std::promise<void>* promise = static_cast<std::promise<void>*>(promise_cookie);
+    promise->set_value();
+}
+
+static void OnBinderUnlinked(void* promise_cookie) {
+    LOG(INFO) << "Cleaning-up the cookie on unlinking death recipient..";
+    delete static_cast<std::promise<void>*>(promise_cookie);
+}
+
+class WeaverKillSecureElementParamTest : public ::testing::TestWithParam<int> {};
+
+TEST_P(WeaverKillSecureElementParamTest, WeaverRecoversAfterSecureElementServiceRestarts) {
+    SCOPED_TRACE(::testing::Message() << "Iteration " << GetParam());
+    LOG(INFO) << "Starting iteration " << GetParam();
+
+    // Get the initial PID of the Secure Element Service
+    const int initial_pid = GetSecureElementServicePid();
+    ASSERT_GT(initial_pid, 0) << "The Secure Element Service is not running.";
+    LOG(INFO) << "The Secure Element Service's PID: " << initial_pid;
+
+    // Register a death recipient with the Secure Element Service to confirm
+    // that the service triggers a death notification after it is killed
+    ndk::SpAIBinder se_binder(AServiceManager_getService(SECURE_ELEMENT_SERVICE_NAME));
+    ASSERT_NE(se_binder.get(), nullptr)
+        << "Failed to get the Secure Element Service binder.";
+    // Use promise/future objects to communicate if a death notification is received.
+    // The death recipient will own and set the promise object while the test will
+    // wait on the associated future object.
+    std::promise<void> *death_promise = new std::promise<void>();
+    auto death_future = death_promise->get_future();
+    auto death_recipient = ndk::ScopedAIBinder_DeathRecipient(
+                                    AIBinder_DeathRecipient_new(OnBinderDied));
+    AIBinder_DeathRecipient_setOnUnlinked(death_recipient.get(), OnBinderUnlinked);
+    auto link_status = AIBinder_linkToDeath(se_binder.get(), death_recipient.get(),
+                                            static_cast<void*>(death_promise));
+    ASSERT_EQ(link_status, STATUS_OK) << "AIBinder_linkToDeath() failed.";
+
+    // Kill the Secure Element Service
+    LOG(INFO) << "Killing the Secure Element Service..";
+    ASSERT_EQ(kill(initial_pid, SIGKILL), 0) << "Failed to kill the service.";
+
+    // Verify that a death notification is received
+    LOG(INFO) << "Waiting for a death notification..";
+    const int kDeathNotificationTimeoutSec = 5;
+    auto future_status = death_future.wait_for(
+                            std::chrono::seconds(kDeathNotificationTimeoutSec));
+    ASSERT_EQ(future_status, std::future_status::ready)
+        << "Did not receive a death notification within "
+        << kDeathNotificationTimeoutSec << " seconds.";
+    LOG(INFO) << "Successfully received a death notification.";
+
+    // Confirm that the Secure Element Service recovers with a new PID
+    int new_pid = 0;
+    const int kMaxRetries = 100;  // 100 * 100ms = 10 seconds timeout
+    constexpr auto kRetryDelay = std::chrono::milliseconds(100);
+    for (int i = 0; i < kMaxRetries; ++i) {
+        std::this_thread::sleep_for(kRetryDelay);
+        new_pid = GetSecureElementServicePid();
+        if (new_pid > 0 && new_pid != initial_pid) {
+            break;
+        }
+    }
+    ASSERT_GT(new_pid, 0) << "The Secure Element Service did not restart.";
+    ASSERT_NE(new_pid, initial_pid)
+            << "The Secure Element Service did not restart (has the same PID).";
+    LOG(INFO) << "The Secure Element Service recovered with new PID: " << new_pid;
+
+    // Check that the Weaver HAL is still responding, with a 5-second timeout.
+    // A small delay to allow Weaver to process the death notification.
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+    const int kWeaverHalTimeoutSec = 5;
+    auto future = std::async(std::launch::async, CheckWeaverHalIsResponding);
+    if (future.wait_for(std::chrono::seconds(kWeaverHalTimeoutSec))
+                                            == std::future_status::timeout) {
+        FAIL() << "The Weaver HAL did not respond for too long (timeout="
+                        << kWeaverHalTimeoutSec << "seconds)";
+    } else {
+        ASSERT_TRUE(future.get());
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(Repeat5Times, WeaverKillSecureElementParamTest, ::testing::Range(1, 6));
+
+int main(int argc, char** argv) {
+    testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}