/* * 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 #include #include #include #include #include #define TIPC_DEV "/dev/trusty-ipc-dev0" #define CRASHER_PORT "com.android.trusty.metrics.test.crasher" namespace android { namespace trusty { namespace metrics { using android::base::unique_fd; static void TriggerCrash() { size_t num_retries = 6; int fd = -1; for (size_t i = 0; i < num_retries; i++) { /* It's possible to time out waiting for crasher TA to restart. */ fd = tipc_connect(TIPC_DEV, CRASHER_PORT); if (fd >= 0) { break; } } unique_fd crasher(fd); ASSERT_GE(crasher, 0); int msg = 0; int rc = write(crasher, &msg, sizeof(msg)); ASSERT_EQ(rc, sizeof(msg)); } class TrustyMetricsTest : public TrustyMetrics, public ::testing::Test { public: TrustyMetricsTest() : TrustyMetrics(TIPC_DEV) {} virtual void HandleCrash(const std::string& app_id) override { crashed_app_ = app_id; } virtual void HandleEventDrop() override { event_drop_count_++; } virtual void SetUp() override { auto ret = Open(); ASSERT_TRUE(ret.ok()) << ret.error(); /* Drain events (if any) and reset state */ DrainEvents(); crashed_app_.clear(); event_drop_count_ = 0; } void DrainEvents() { while (WaitForEvent(1000 /* 1 second timeout */).ok()) { auto ret = HandleEvent(); ASSERT_TRUE(ret.ok()) << ret.error(); } } void WaitForAndHandleEvent() { auto ret = WaitForEvent(30000 /* 30 second timeout */); ASSERT_TRUE(ret.ok()) << ret.error(); ret = HandleEvent(); ASSERT_TRUE(ret.ok()) << ret.error(); } std::string crashed_app_; size_t event_drop_count_; }; TEST_F(TrustyMetricsTest, Crash) { TriggerCrash(); WaitForAndHandleEvent(); /* Check that no event was dropped. */ ASSERT_EQ(event_drop_count_, 0); /* Check that correct TA crashed. */ ASSERT_EQ(crashed_app_, "36f5b435-5bd3-4526-8b76-200e3a7e79f3:crasher"); } TEST_F(TrustyMetricsTest, PollSet) { int binder_fd; int rc = IPCThreadState::self()->setupPolling(&binder_fd); ASSERT_EQ(rc, 0); ASSERT_GE(binder_fd, 0); TriggerCrash(); struct pollfd pfds[] = { { .fd = binder_fd, .events = POLLIN, }, { .fd = GetRawFd(), .events = POLLIN, }, }; rc = poll(pfds, 2, 30000 /* 30 second timeout */); /* We expect one event on the metrics fd. */ ASSERT_EQ(rc, 1); ASSERT_TRUE(pfds[1].revents & POLLIN); auto ret = HandleEvent(); ASSERT_TRUE(ret.ok()) << ret.error(); /* Check that no event was dropped. */ ASSERT_EQ(event_drop_count_, 0); /* Check that correct TA crashed. */ ASSERT_EQ(crashed_app_, "36f5b435-5bd3-4526-8b76-200e3a7e79f3:crasher"); } TEST_F(TrustyMetricsTest, EventDrop) { /* We know the size of the internal event queue is less than this. */ size_t num_events = 3; ASSERT_EQ(event_drop_count_, 0); for (auto i = 0; i < num_events; i++) { TriggerCrash(); } for (auto i = 0; i < num_events; i++) { WaitForAndHandleEvent(); if (event_drop_count_ > 0) { break; } } ASSERT_EQ(event_drop_count_, 1); } } // namespace metrics } // namespace trusty } // namespace android