1 /*
2  * Copyright (C) 2024 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 #define LOG_TAG "test_multiple_close_simultaneously"
18 
19 #include <chrono>
20 #include <condition_variable>
21 #include <shared_mutex>
22 #include <string>
23 #include <thread>
24 
25 #include <gtest/gtest.h>
26 
27 #include <binder/IBinder.h>
28 #include <binder/IServiceManager.h>
29 #include <utils/Log.h>
30 
31 #include <aaudio/AAudio.h>
32 #include <aaudio/IAAudioService.h>
33 #include <aaudio/StreamRequest.h>
34 #include <aaudio/StreamParameters.h>
35 
36 using namespace android;
37 using namespace aaudio;
38 
39 #define AAUDIO_SERVICE_NAME "media.aaudio"
40 
41 static constexpr int THREAD_NUM = 2;
42 static constexpr auto TEST_DURATION = std::chrono::minutes(1);
43 
44 static std::string sError;
45 static bool sTestPassed = true;
46 
47 struct Signal {
48     std::atomic_int value{0};
49     std::shared_mutex lock;
50     std::condition_variable_any cv;
51 };
52 
53 class AAudioServiceDeathRecipient : public IBinder::DeathRecipient {
54 public:
binderDied(const wp<IBinder> & who __unused)55     void binderDied(const wp<IBinder>& who __unused) override {
56         sError = "AAudioService is dead";
57         ALOGE("%s", sError.c_str());
58         sTestPassed = false;
59     }
60 };
61 
getAAudioService(const sp<IBinder::DeathRecipient> & recipient)62 sp<IAAudioService> getAAudioService(const sp<IBinder::DeathRecipient>& recipient) {
63     auto sm = defaultServiceManager();
64     if (sm == nullptr) {
65         sError = "Cannot get service manager";
66         ALOGE("%s", sError.c_str());
67         return nullptr;
68     }
69     sp<IBinder> binder = sm->waitForService(String16(AAUDIO_SERVICE_NAME));
70     if (binder == nullptr) {
71         sError = "Cannot get aaudio service";
72         ALOGE("%s", sError.c_str());
73         return nullptr;
74     }
75     if (binder->linkToDeath(recipient) != NO_ERROR) {
76         sError = "Cannot link to binder death";
77         ALOGE("%s", sError.c_str());
78         return nullptr;
79     }
80     return interface_cast<IAAudioService>(binder);
81 }
82 
openAndMultipleClose(const sp<IAAudioService> & aaudioService)83 void openAndMultipleClose(const sp<IAAudioService>& aaudioService) {
84     auto start = std::chrono::system_clock::now();
85     bool hasFailedOpening = false;
86     while (sTestPassed && std::chrono::system_clock::now() - start < TEST_DURATION) {
87         StreamRequest inRequest;
88         StreamParameters outParams;
89         int32_t handle = 0;
90         inRequest.attributionSource.uid = getuid();
91         inRequest.attributionSource.pid = getpid();
92         inRequest.attributionSource.token = sp<BBinder>::make();
93         auto status = aaudioService->openStream(inRequest, &outParams, &handle);
94         if (!status.isOk()) {
95             sError = "Cannot open stream, it can be caused by service death";
96             ALOGE("%s", sError.c_str());
97             sTestPassed = false;
98             break;
99         }
100         if (handle <= 0) {
101             sError = "Cannot get stream handle after open, returned handle"
102                     + std::to_string(handle);
103             ALOGE("%s", sError.c_str());
104             sTestPassed = false;
105             break;
106         }
107         hasFailedOpening = false;
108 
109         Signal isReady;
110         Signal startWork;
111         Signal isCompleted;
112         std::unique_lock readyLock(isReady.lock);
113         std::unique_lock completedLock(isCompleted.lock);
114         for (int i = 0; i < THREAD_NUM; ++i) {
115             std::thread closeStream([aaudioService, handle, &isReady, &startWork, &isCompleted] {
116                 isReady.value++;
117                 isReady.cv.notify_one();
118                 {
119                     std::shared_lock<std::shared_mutex> _l(startWork.lock);
120                     startWork.cv.wait(_l, [&startWork] { return startWork.value.load() == 1; });
121                 }
122                 int32_t result;
123                 aaudioService->closeStream(handle, &result);
124                 isCompleted.value++;
125                 isCompleted.cv.notify_one();
126             });
127             closeStream.detach();
128         }
129         isReady.cv.wait(readyLock, [&isReady] { return isReady.value == THREAD_NUM; });
130         {
131             std::unique_lock startWorkLock(startWork.lock);
132             startWork.value.store(1);
133         }
134         startWork.cv.notify_all();
135         isCompleted.cv.wait_for(completedLock,
136                                 std::chrono::milliseconds(1000),
137                                 [&isCompleted] { return isCompleted.value == THREAD_NUM; });
138         if (isCompleted.value != THREAD_NUM) {
139             sError = "Close is not completed within 1 second";
140             ALOGE("%s", sError.c_str());
141             sTestPassed = false;
142             break;
143         }
144     }
145 }
146 
TEST(test_multiple_close_simultaneously,open_multiple_close)147 TEST(test_multiple_close_simultaneously, open_multiple_close) {
148     const auto recipient = sp<AAudioServiceDeathRecipient>::make();
149     auto aaudioService = getAAudioService(recipient);
150     ASSERT_NE(nullptr, aaudioService) << sError;
151     openAndMultipleClose(aaudioService);
152     ASSERT_TRUE(sTestPassed) << sError;
153 }
154