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