1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <unistd.h>
18 
19 #include <chrono>
20 #include <set>
21 #include <string>
22 #include <thread>
23 
24 #include <aidl/Gtest.h>
25 #include <aidl/Vintf.h>
26 #include <aidl/android/hardware/health/storage/BnGarbageCollectCallback.h>
27 #include <aidl/android/hardware/health/storage/IStorage.h>
28 #include <android-base/logging.h>
29 #include <android/binder_ibinder.h>
30 #include <android/binder_manager.h>
31 #include <android/binder_process.h>
32 #include <gtest/gtest.h>
33 #include <health-storage-test/common.h>
34 
35 namespace aidl::android::hardware::health::storage {
36 
37 using namespace ::android::hardware::health::storage::test;
38 using std::chrono_literals::operator""ms;
39 
40 #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) << ret.getDescription()
41 #define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk()) << ret.getDescription()
42 
43 class GcCallback : public BnGarbageCollectCallback, public Flag {
44   public:
onFinish(Result result)45     ndk::ScopedAStatus onFinish(Result result) override {
46         std::unique_lock<std::mutex> lock(mutex_);
47         result_ = result;
48         OnFinishLocked(&lock);
49         return ndk::ScopedAStatus::ok();
50     }
51 
52     /**
53      * Wait for a specific "timeout". If GC has finished, test that the result
54      * is equal to the "expected" value.
55      */
56     template <typename R, typename P>
WaitForResult(std::chrono::duration<R,P> timeout,Result expected)57     void WaitForResult(std::chrono::duration<R, P> timeout, Result expected) {
58         std::unique_lock<std::mutex> lock(mutex_);
59         ASSERT_TRUE(WaitLocked(&lock, timeout)) << "timeout after " << to_string(timeout);
60         EXPECT_EQ(expected, result_);
61     }
62 
63   private:
64     Result result_{Result::UNKNOWN_ERROR};
65 };
66 
67 class HealthStorageAidl : public testing::TestWithParam<std::string> {
68   public:
SetUp()69     virtual void SetUp() override {
70         std::string name = GetParam();
71         ASSERT_TRUE(AServiceManager_isDeclared(name.c_str())) << name;
72         ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str()));
73         ASSERT_NE(binder, nullptr);
74         storage_ = IStorage::fromBinder(binder);
75         ASSERT_NE(storage_, nullptr);
76     }
77 
TearDown()78     virtual void TearDown() override {
79         EXPECT_TRUE(ping(kRpcTime))
80                 << "Service is not responsive; expect subsequent tests to fail.";
81     }
82 
83     /**
84      * Ping the service and expect it to return after "timeout". Return true
85      * iff the service is responsive within "timeout".
86      */
87     template <typename R, typename P>
ping(std::chrono::duration<R,P> timeout)88     bool ping(std::chrono::duration<R, P> timeout) {
89         // Ensure the service is responsive after the test.
90         std::shared_ptr<IStorage> service = storage_;
91         auto ping_flag = std::make_shared<Flag>();
92         std::thread([service, ping_flag] {
93             EXPECT_EQ(STATUS_OK, AIBinder_ping(service->asBinder().get()));
94             ping_flag->OnFinish();
95         }).detach();
96         return ping_flag->Wait(timeout);
97     }
98 
99     std::shared_ptr<IStorage> storage_;
100 };
101 
102 /**
103  * Ensure garbage collection works on null callback.
104  */
TEST_P(HealthStorageAidl,GcNullCallback)105 TEST_P(HealthStorageAidl, GcNullCallback) {
106     ASSERT_OK(storage_->garbageCollect(kDevGcTimeoutSec, nullptr));
107 
108     // Hold test process because HAL can be single-threaded and doing GC.
109     ASSERT_TRUE(ping(kDevGcTimeout + kDevGcTolerance + kRpcTime))
110             << "Service must be available after "
111             << to_string(kDevGcTimeout + kDevGcTolerance + kRpcTime);
112 }
113 
114 /**
115  * Ensure garbage collection works on non-null callback.
116  */
TEST_P(HealthStorageAidl,GcNonNullCallback)117 TEST_P(HealthStorageAidl, GcNonNullCallback) {
118     std::shared_ptr<GcCallback> cb = ndk::SharedRefBase::make<GcCallback>();
119     ASSERT_OK(storage_->garbageCollect(kDevGcTimeoutSec, cb));
120     cb->WaitForResult(kDevGcTimeout + kDevGcTolerance + kRpcTime, Result::SUCCESS);
121 }
122 
123 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HealthStorageAidl);
124 INSTANTIATE_TEST_SUITE_P(
125         HealthStorage, HealthStorageAidl,
126         testing::ValuesIn(::android::getAidlHalInstanceNames(IStorage::descriptor)),
127         ::android::PrintInstanceNameToString);
128 
129 }  // namespace aidl::android::hardware::health::storage
130 
main(int argc,char ** argv)131 int main(int argc, char** argv) {
132     ::testing::InitGoogleTest(&argc, argv);
133     ABinderProcess_setThreadPoolMaxThreadCount(1);
134     ABinderProcess_startThreadPool();
135     return RUN_ALL_TESTS();
136 }
137