1 /*
2 * Copyright (C) 2022 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 "chre_api/chre/re.h"
18
19 #include <cstdint>
20
21 #include "chre/core/event_loop_manager.h"
22 #include "chre/core/settings.h"
23 #include "chre/platform/log.h"
24 #include "chre/util/time.h"
25 #include "chre_api/chre/event.h"
26
27 #include "gtest/gtest.h"
28 #include "inc/test_util.h"
29 #include "test_base.h"
30 #include "test_event.h"
31 #include "test_event_queue.h"
32 #include "test_util.h"
33
34 namespace chre {
35
36 // TimerTest is required to access private members of the TimerPool.
37 class TimerTest : public TestBase {
38 protected:
hasNanoappTimers(TimerPool & pool,uint16_t instanceId)39 bool hasNanoappTimers(TimerPool &pool, uint16_t instanceId) {
40 return pool.hasNanoappTimers(instanceId);
41 }
42 };
43
44 namespace {
45
TEST_F(TimerTest,SetupAndCancelPeriodicTimer)46 TEST_F(TimerTest, SetupAndCancelPeriodicTimer) {
47 CREATE_CHRE_TEST_EVENT(START_TIMER, 0);
48 CREATE_CHRE_TEST_EVENT(STOP_TIMER, 1);
49
50 class App : public TestNanoapp {
51 public:
52 void handleEvent(uint32_t, uint16_t eventType,
53 const void *eventData) override {
54 switch (eventType) {
55 case CHRE_EVENT_TIMER: {
56 auto data = static_cast<const uint32_t *>(eventData);
57 if (*data == mCookie) {
58 mCount++;
59 if (mCount == 3) {
60 TestEventQueueSingleton::get()->pushEvent(CHRE_EVENT_TIMER);
61 }
62 }
63 break;
64 }
65
66 case CHRE_EVENT_TEST_EVENT: {
67 auto event = static_cast<const TestEvent *>(eventData);
68 switch (event->type) {
69 case START_TIMER: {
70 uint32_t handle = chreTimerSet(10 * kOneMillisecondInNanoseconds,
71 &mCookie, false /*oneShot*/);
72 TestEventQueueSingleton::get()->pushEvent(START_TIMER, handle);
73 break;
74 }
75 case STOP_TIMER: {
76 auto handle = static_cast<const uint32_t *>(event->data);
77 bool success = chreTimerCancel(*handle);
78 TestEventQueueSingleton::get()->pushEvent(STOP_TIMER, success);
79 break;
80 }
81 }
82 }
83 }
84 }
85
86 protected:
87 const uint32_t mCookie = 123;
88 int mCount = 0;
89 };
90
91 uint64_t appId = loadNanoapp(MakeUnique<App>());
92
93 TimerPool &timerPool =
94 EventLoopManagerSingleton::get()->getEventLoop().getTimerPool();
95
96 uint16_t instanceId;
97 EXPECT_TRUE(EventLoopManagerSingleton::get()
98 ->getEventLoop()
99 .findNanoappInstanceIdByAppId(appId, &instanceId));
100
101 uint32_t handle;
102 sendEventToNanoapp(appId, START_TIMER);
103 waitForEvent(START_TIMER, &handle);
104 EXPECT_NE(handle, CHRE_TIMER_INVALID);
105 EXPECT_TRUE(hasNanoappTimers(timerPool, instanceId));
106
107 waitForEvent(CHRE_EVENT_TIMER);
108
109 bool success;
110
111 // Cancelling an active timer should be successful.
112 sendEventToNanoapp(appId, STOP_TIMER, handle);
113 waitForEvent(STOP_TIMER, &success);
114 EXPECT_TRUE(success);
115 EXPECT_FALSE(hasNanoappTimers(timerPool, instanceId));
116
117 // Cancelling an inactive time should return false.
118 sendEventToNanoapp(appId, STOP_TIMER, handle);
119 waitForEvent(STOP_TIMER, &success);
120 EXPECT_FALSE(success);
121 }
122
TEST_F(TimerTest,CancelPeriodicTimerOnUnload)123 TEST_F(TimerTest, CancelPeriodicTimerOnUnload) {
124 CREATE_CHRE_TEST_EVENT(START_TIMER, 0);
125
126 class App : public TestNanoapp {
127 public:
128 void handleEvent(uint32_t, uint16_t eventType, const void *eventData) {
129 switch (eventType) {
130 case CHRE_EVENT_TIMER: {
131 auto data = static_cast<const uint32_t *>(eventData);
132 if (*data == mCookie) {
133 mCount++;
134 if (mCount == 3) {
135 TestEventQueueSingleton::get()->pushEvent(CHRE_EVENT_TIMER);
136 }
137 }
138 break;
139 }
140
141 case CHRE_EVENT_TEST_EVENT: {
142 auto event = static_cast<const TestEvent *>(eventData);
143 switch (event->type) {
144 case START_TIMER: {
145 uint32_t handle = chreTimerSet(10 * kOneMillisecondInNanoseconds,
146 &mCookie, false /*oneShot*/);
147 TestEventQueueSingleton::get()->pushEvent(START_TIMER, handle);
148 break;
149 }
150 }
151 }
152 }
153 }
154
155 protected:
156 const uint32_t mCookie = 123;
157 int mCount = 0;
158 };
159
160 uint64_t appId = loadNanoapp(MakeUnique<App>());
161
162 TimerPool &timerPool =
163 EventLoopManagerSingleton::get()->getEventLoop().getTimerPool();
164
165 uint16_t instanceId;
166 EXPECT_TRUE(EventLoopManagerSingleton::get()
167 ->getEventLoop()
168 .findNanoappInstanceIdByAppId(appId, &instanceId));
169
170 uint32_t handle;
171 sendEventToNanoapp(appId, START_TIMER);
172 waitForEvent(START_TIMER, &handle);
173 EXPECT_NE(handle, CHRE_TIMER_INVALID);
174 EXPECT_TRUE(hasNanoappTimers(timerPool, instanceId));
175
176 waitForEvent(CHRE_EVENT_TIMER);
177
178 unloadNanoapp(appId);
179 EXPECT_FALSE(hasNanoappTimers(timerPool, instanceId));
180 }
181
182 } // namespace
183 } // namespace chre
184