xref: /aosp_15_r20/frameworks/av/media/utils/tests/service_singleton_tests.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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 "service_singleton_tests"
18 
19 #include <mediautils/ServiceSingleton.h>
20 
21 #include "BnServiceSingletonTest.h"
22 #include "aidl/BnServiceSingletonTest.h"
23 #include <audio_utils/RunRemote.h>
24 #include <binder/IPCThreadState.h>
25 #include <binder/ProcessState.h>
26 #include <gtest/gtest.h>
27 #include <utils/Log.h>
28 
29 using namespace android;
30 
31 /**
32  * Service Singleton Test uses a worker process to spawn new binder services.
33  *
34  * A worker process is required since we cannot fork after registering
35  * with the binder driver.
36  *
37  * Test Process -> Worker_Process -> Service Process(1)
38  *                                -> Service Process(2)
39  *                                -> ....
40  */
41 
42 // Service implementation.
43 class ServiceSingletonTestCpp : public BnServiceSingletonTest {
44 public:
inc(int32_t * _aidl_return)45     binder::Status inc(int32_t* _aidl_return) final {
46         *_aidl_return = ++mValue;
47         return binder::Status::ok();
48     }
49     std::atomic_int32_t mValue = 0;
50 };
51 
52 // The service traits increment static atomic counters, which
53 // validates that the trait callbacks are invoked.
54 static std::atomic_int32_t sNewService = 0;
55 static std::atomic_int32_t sServiceDied = 0;
56 
57 template <typename Service>
58 struct TestServiceTraits : public mediautils::DefaultServiceTraits<Service> {
getServiceNameTestServiceTraits59     static constexpr const char* getServiceName() { return ""; }
onNewServiceTestServiceTraits60     static constexpr void onNewService(const mediautils::InterfaceType<Service>&) {
61         ++sNewService;
62     }
onServiceDiedTestServiceTraits63     static constexpr void onServiceDied(const mediautils::InterfaceType<Service>&) {
64         ++sServiceDied;
65     }
66 };
67 
68 // Here we have an alternative set of service traits,
69 // used to validate that we can switch traits for the service singleton.
70 static std::atomic_int32_t sNewService2 = 0;
71 static std::atomic_int32_t sServiceDied2 = 0;
72 
73 template <typename Service>
74 struct TestServiceTraits2 : public mediautils::DefaultServiceTraits<Service> {
getServiceNameTestServiceTraits275     static constexpr const char* getServiceName() { return ""; }
onNewServiceTestServiceTraits276     static constexpr void onNewService(const mediautils::InterfaceType<Service>&) {
77         ++sNewService2;
78     }
onServiceDiedTestServiceTraits279     static constexpr void onServiceDied(const mediautils::InterfaceType<Service>&) {
80         ++sServiceDied2;
81     }
82 };
83 
84 /*
85  * ServiceThreads run in a remote process.
86  *
87  * The WorkerThread is used to launch and kill the ServiceThread in a remote process.
88  */
ServiceThread(audio_utils::RunRemote & runRemote)89 static void ServiceThread(audio_utils::RunRemote& runRemote) {
90     int c = runRemote.getc();  // requires any character to launch
91     auto service = sp<IServiceSingletonTest>::cast(sp<ServiceSingletonTestCpp>::make());
92     mediautils::addService(service);
93     ProcessState::self()->startThreadPool();
94     runRemote.putc(c);  // echo character.
95     IPCThreadState::self()->joinThreadPool();
96 }
97 
98 /*
99  * The WorkerThread is run in a remote process from the test.  It communicates with
100  * the test process through pipes.
101  */
WorkerThread(audio_utils::RunRemote & runRemote)102 static void WorkerThread(audio_utils::RunRemote& runRemote) {
103     std::shared_ptr<audio_utils::RunRemote> remoteService;
104     while (true) {
105         const int c = runRemote.getc();
106         switch (c) {
107             case 'a':  // launch a new service.
108                 // if the old service isn't destroyed, it will be destroyed here
109                 // when the RunRemote is replaced.
110                 remoteService = std::make_shared<audio_utils::RunRemote>(ServiceThread);
111                 remoteService->run();
112                 remoteService->putc('a');  // create service.
113                 (void)remoteService->getc(); // ensure it is created.
114                 runRemote.putc(c);  // echo
115                 break;
116             case 'b':  // destroys the old service.
117                 remoteService.reset();  // this kills the service.
118                 runRemote.putc(c);  // echo
119                 break;
120             default:  // respond that we don't know what happened!
121                 runRemote.putc('?');
122                 break;
123         }
124     }
125 }
126 
127 // This is a monolithic test.
TEST(service_singleton_tests,one_and_only)128 TEST(service_singleton_tests, one_and_only) {
129     std::atomic_int32_t listenerServiceCreated = 0;
130     std::atomic_int32_t listenerServiceDied = 0;
131 
132     // initialize the service cache with a custom handler.
133     mediautils::initService<
134         IServiceSingletonTest, TestServiceTraits<IServiceSingletonTest>>({});
135     mediautils::initService<
136         aidl::IServiceSingletonTest, TestServiceTraits<aidl::IServiceSingletonTest>>({});
137 
138     // start the worker thread that spawns the services.
139     auto remoteWorker = std::make_shared<audio_utils::RunRemote>(WorkerThread);
140     remoteWorker->run();
141 
142     // now we are ready for binder.
143     ProcessState::self()->startThreadPool();
144 
145     // check that our service isn't preexisting.
146     {
147         auto service = mediautils::checkServicePassThrough<IServiceSingletonTest>();
148         EXPECT_FALSE(service);
149 
150         auto service2 = mediautils::checkServicePassThrough<aidl::IServiceSingletonTest>();
151         EXPECT_FALSE(service2);
152     }
153     EXPECT_EQ(0, sNewService);
154     EXPECT_EQ(0, sServiceDied);
155 
156     {
157         auto service = mediautils::checkService<IServiceSingletonTest>();
158         EXPECT_FALSE(service);
159 
160         auto service2 = mediautils::checkService<aidl::IServiceSingletonTest>();
161         EXPECT_FALSE(service2);
162     }
163     EXPECT_EQ(0, sNewService);
164     EXPECT_EQ(0, sServiceDied);
165 
166     // getService will register a notification handler that fetches the
167     // service in the background.
168     {
169         auto service = mediautils::getService<IServiceSingletonTest>();
170         EXPECT_FALSE(service);
171 
172         auto service2 = mediautils::getService<aidl::IServiceSingletonTest>();
173         EXPECT_FALSE(service2);
174     }
175     EXPECT_EQ(0, sNewService);
176     EXPECT_EQ(0, sServiceDied);
177 
178     // now spawn the service.
179     remoteWorker->putc('a');
180     EXPECT_EQ('a', remoteWorker->getc());
181 
182     sleep(1);  // In the background, 2 services were fetched.
183 
184     EXPECT_EQ(2, sNewService);
185     EXPECT_EQ(0, sServiceDied);
186 
187     // we repeat the prior checks, but the service is cached now.
188     {
189         auto service = mediautils::checkServicePassThrough<IServiceSingletonTest>();
190         EXPECT_TRUE(service);
191 
192         auto service2 = mediautils::checkServicePassThrough<aidl::IServiceSingletonTest>();
193         EXPECT_TRUE(service2);
194     }
195     EXPECT_EQ(2, sNewService);
196     EXPECT_EQ(0, sServiceDied);
197 
198     {
199         auto service = mediautils::checkService<IServiceSingletonTest>();
200         EXPECT_TRUE(service);
201 
202         auto service2 = mediautils::checkService<aidl::IServiceSingletonTest>();
203         EXPECT_TRUE(service2);
204     }
205     EXPECT_EQ(2, sNewService);
206     EXPECT_EQ(0, sServiceDied);
207 
208     {
209         auto service = mediautils::getService<IServiceSingletonTest>();
210         EXPECT_TRUE(service);
211 
212         auto service2 = mediautils::getService<aidl::IServiceSingletonTest>();
213         EXPECT_TRUE(service2);
214     }
215     EXPECT_EQ(2, sNewService);
216     EXPECT_EQ(0, sServiceDied);
217 
218     // destroy the service.
219     remoteWorker->putc('b');
220     EXPECT_EQ('b', remoteWorker->getc());
221 
222     sleep(1);
223 
224     // We expect the died callbacks.
225     EXPECT_EQ(2, sNewService);
226     EXPECT_EQ(2, sServiceDied);
227 
228     // we can also manually check whether there is a new service by
229     // requesting service notifications.  This is outside of the service singleton
230     // traits.
231     auto handle1 = mediautils::requestServiceNotification<IServiceSingletonTest>(
232             [&](const sp<IServiceSingletonTest>&) { ++listenerServiceCreated; });
233     auto handle2 = mediautils::requestServiceNotification<aidl::IServiceSingletonTest>(
234             [&](const std::shared_ptr<aidl::IServiceSingletonTest>&) {
235                 ++listenerServiceCreated; });
236 
237     // Spawn the service again.
238     remoteWorker->putc('a');
239     EXPECT_EQ('a', remoteWorker->getc());
240 
241     sleep(1);  // In the background, 2 services were fetched.
242 
243     EXPECT_EQ(4, sNewService);
244     EXPECT_EQ(2, sServiceDied);
245 
246     EXPECT_EQ(2, listenerServiceCreated);  // our listener picked up the service creation.
247 
248     std::shared_ptr<void> handle3, handle4;
249     std::shared_ptr<aidl::IServiceSingletonTest> keepAlive;  // NDK Workaround!
250     {
251         auto service = mediautils::getService<IServiceSingletonTest>();
252         EXPECT_TRUE(service);
253 
254         auto service2 = mediautils::getService<aidl::IServiceSingletonTest>();
255         EXPECT_TRUE(service2);
256 
257         keepAlive = service2;
258 
259         // we can also request our own death notifications (outside of the service traits).
260         handle3 = mediautils::requestDeathNotification(service, [&] { ++listenerServiceDied; });
261         EXPECT_TRUE(handle3);
262         handle4 = mediautils::requestDeathNotification(service2, [&] { ++listenerServiceDied; });
263         EXPECT_TRUE(handle4);
264     }
265 
266     EXPECT_EQ(4, sNewService);
267     EXPECT_EQ(2, sServiceDied);
268 
269     // destroy the service.
270 
271     remoteWorker->putc('b');
272     EXPECT_EQ('b', remoteWorker->getc());
273 
274     sleep(1);
275 
276     // We expect the died callbacks.
277     EXPECT_EQ(4, sNewService);
278     EXPECT_EQ(4, sServiceDied);
279 
280     EXPECT_EQ(2, listenerServiceCreated);
281     EXPECT_EQ(2, listenerServiceDied);  // NDK Workaround - without keepAlive, this is 1.
282                                         // the death notification is invalidated without a
283                                         // pointer to the binder object.
284 
285     keepAlive.reset();
286 
287     // Cancel the singleton cache.
288     mediautils::skipService<IServiceSingletonTest>();
289     mediautils::skipService<aidl::IServiceSingletonTest>();
290 
291     // Spawn the service again.
292     remoteWorker->putc('a');
293     EXPECT_EQ('a', remoteWorker->getc());
294 
295     sleep(1);
296 
297     // We expect no change from the service traits (service not cached).
298     EXPECT_EQ(4, sNewService);
299     EXPECT_EQ(4, sServiceDied);
300     EXPECT_EQ(4, listenerServiceCreated);  // our listener picks it up.
301 
302     {
303         // in default mode (kNull) a null is returned when the service is skipped and
304         // wait time is ignored.
305 
306         const auto ref1 = std::chrono::steady_clock::now();
307         auto service = mediautils::getService<IServiceSingletonTest>(std::chrono::seconds(2));
308         EXPECT_FALSE(service);
309         const auto ref2 = std::chrono::steady_clock::now();
310         EXPECT_LT(ref2 - ref1, std::chrono::seconds(1));
311 
312         auto service2 = mediautils::getService<aidl::IServiceSingletonTest>(
313                 std::chrono::seconds(2));
314         EXPECT_FALSE(service2);
315         const auto ref3 = std::chrono::steady_clock::now();
316         EXPECT_LT(ref3 - ref2, std::chrono::seconds(1));
317     }
318 
319     // Cancel the singleton cache but use wait mode.
320     mediautils::skipService<IServiceSingletonTest>(mediautils::SkipMode::kWait);
321     mediautils::skipService<aidl::IServiceSingletonTest>(mediautils::SkipMode::kWait);
322 
323     {
324         // in wait mode, the timeouts are respected
325         const auto ref1 = std::chrono::steady_clock::now();
326         auto service = mediautils::getService<IServiceSingletonTest>(std::chrono::seconds(1));
327         EXPECT_FALSE(service);
328         const auto ref2 = std::chrono::steady_clock::now();
329         EXPECT_GT(ref2 - ref1, std::chrono::seconds(1));
330 
331         auto service2 = mediautils::getService<aidl::IServiceSingletonTest>(
332                 std::chrono::seconds(1));
333         EXPECT_FALSE(service2);
334         const auto ref3 = std::chrono::steady_clock::now();
335         EXPECT_GT(ref3 - ref2, std::chrono::seconds(1));
336     }
337 
338     // remove service
339     remoteWorker->putc('b');
340     EXPECT_EQ('b', remoteWorker->getc());
341 
342     sleep(1);
343 
344     // We expect no change from the service traits (service not cached).
345     EXPECT_EQ(4, sNewService);
346     EXPECT_EQ(4, sServiceDied);
347     EXPECT_EQ(4, listenerServiceCreated);
348     EXPECT_EQ(2, listenerServiceDied);  // binder died is associated with the actual handle.
349 
350     // replace the service traits.
351     {
352         auto previous = mediautils::initService<
353                 IServiceSingletonTest, TestServiceTraits2<IServiceSingletonTest>>({});
354         auto previous2 = mediautils::initService<
355                 aidl::IServiceSingletonTest, TestServiceTraits2<aidl::IServiceSingletonTest>>({});
356 
357         EXPECT_FALSE(previous);
358         EXPECT_FALSE(previous2);
359     }
360 
361     // We expect no change with old counters.
362     EXPECT_EQ(4, sNewService);
363     EXPECT_EQ(4, sServiceDied);
364     EXPECT_EQ(0, sNewService2);
365     EXPECT_EQ(0, sServiceDied2);
366 
367     {
368         auto service = mediautils::getService<IServiceSingletonTest>();
369         EXPECT_FALSE(service);
370 
371         auto service2 = mediautils::getService<aidl::IServiceSingletonTest>();
372         EXPECT_FALSE(service2);
373     }
374 
375     EXPECT_EQ(4, sNewService);
376     EXPECT_EQ(4, sServiceDied);
377     EXPECT_EQ(0, sNewService2);
378     EXPECT_EQ(0, sServiceDied2);
379 
380     // Spawn the service again.
381     remoteWorker->putc('a');
382     EXPECT_EQ('a', remoteWorker->getc());
383 
384     sleep(1);
385 
386     EXPECT_EQ(4, sNewService);   // old counters do not change.
387     EXPECT_EQ(4, sServiceDied);
388     EXPECT_EQ(2, sNewService2);  // new counters change
389     EXPECT_EQ(0, sServiceDied2);
390 
391     EXPECT_EQ(6, listenerServiceCreated);  // listener associated with service name picks up info.
392 
393     // get service pointers that will be made stale later.
394     auto stale_service = mediautils::getService<IServiceSingletonTest>();
395     EXPECT_TRUE(stale_service);  // not stale yet.
396 
397     auto stale_service2 = mediautils::getService<aidl::IServiceSingletonTest>();
398     EXPECT_TRUE(stale_service2);  // not stale yet.
399 
400     // Release the service.
401     remoteWorker->putc('b');
402     EXPECT_EQ('b', remoteWorker->getc());
403 
404     sleep(1);
405 
406     EXPECT_EQ(4, sNewService);    // old counters do not change.
407     EXPECT_EQ(4, sServiceDied);
408     EXPECT_EQ(2, sNewService2);   // new counters change
409     EXPECT_EQ(2, sServiceDied2);
410 
411     // The service handles are now stale, verify that we can't register a death notification.
412     {
413         std::atomic_int32_t postDied = 0;
414         // we cannot register death notification so handles are null.
415         auto handle1 = mediautils::requestDeathNotification(stale_service, [&] { ++postDied; });
416         EXPECT_FALSE(handle1);
417         auto handle2= mediautils::requestDeathNotification(stale_service2, [&] { ++postDied; });
418         EXPECT_FALSE(handle2);
419         EXPECT_EQ(0, postDied);  // no callbacks issued.
420     }
421 }
422