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 #include <android/content/AttributionSourceState.h>
18 #include <media/AppOpsSession.h>
19 #include <media/ValidatedAttributionSourceState.h>
20
21 #include <gmock/gmock.h>
22 #include <gtest/gtest.h>
23
24 #include <functional>
25
26 using ::android::content::AttributionSourceState;
27 using ::android::media::permission::AppOpsSession;
28 using ::android::media::permission::Ops;
29 using ::com::android::media::permission::ValidatedAttributionSourceState;
30
31 using ::testing::ElementsAreArray;
32 using ::testing::IsEmpty;
33 using ::testing::Ne;
34
35 class AppOpsSessionTests;
36
37 class AppOpsTestFacade {
38 friend AppOpsSessionTests;
39
40 public:
startAccess(const ValidatedAttributionSourceState &,Ops)41 bool startAccess(const ValidatedAttributionSourceState&, Ops) {
42 if (allowed_) ++running_;
43 return allowed_;
44 }
45
stopAccess(const ValidatedAttributionSourceState &,Ops)46 void stopAccess(const ValidatedAttributionSourceState&, Ops) { --running_; }
47
checkAccess(const ValidatedAttributionSourceState &,Ops)48 bool checkAccess(const ValidatedAttributionSourceState&, Ops) { return allowed_; }
49
addChangeCallback(const ValidatedAttributionSourceState &,Ops,std::function<void (bool)> cb)50 uintptr_t addChangeCallback(const ValidatedAttributionSourceState&, Ops,
51 std::function<void(bool)> cb) {
52 cb_ = cb;
53 return 42;
54 }
55
removeChangeCallback(uintptr_t)56 void removeChangeCallback(uintptr_t) {}
57
58 private:
59 // Static abuse since this is copied into the test, and represents "global" state
60 static inline std::function<void(bool)> cb_;
61 static inline bool allowed_;
62 static inline int running_;
63 };
64
65 class AppOpsSessionTests : public ::testing::Test {
66 protected:
67 static constexpr Ops mOps = {100, 101};
68
69 // We must manually clear the facade state, since it is static, unlike the members of this
70 // class, since the fixture is constructed per-test.
SetUp()71 void SetUp() override {
72 AppOpsTestFacade::cb_ = nullptr;
73 AppOpsTestFacade::running_ = 0;
74 AppOpsTestFacade::allowed_ = false;
75 }
76
facadeSetAllowed(bool isAllowed)77 void facadeSetAllowed(bool isAllowed) { AppOpsTestFacade::allowed_ = isAllowed; }
78
facadeGetRunning()79 int facadeGetRunning() { return AppOpsTestFacade::running_; }
80
facadeTriggerChange(bool isPermitted)81 void facadeTriggerChange(bool isPermitted) {
82 EXPECT_THAT(isPermitted, Ne(AppOpsTestFacade::allowed_));
83 facadeSetAllowed(isPermitted);
84 AppOpsTestFacade::cb_(isPermitted);
85 }
86
87 // Trigger a change callback, but without modifying the underlying state.
88 // Allows for simulating a callback which is reversed quickly and callbacks which may not
89 // apply to our package.
facadeTriggerSpuriousChange(bool isPermitted)90 void facadeTriggerSpuriousChange(bool isPermitted) { facadeSetAllowed(isPermitted); }
91
dataDeliveryCb(bool shouldDeliver)92 void dataDeliveryCb(bool shouldDeliver) { mDeliveredCbs.push_back(shouldDeliver); }
93
__anonda944ad80102() 94 const AttributionSourceState mAttr = []() {
95 AttributionSourceState attr;
96 attr.uid = 1;
97 attr.pid = 2;
98 attr.deviceId = 3;
99 return attr;
100 }();
101
initSession()102 void initSession() {
103 mAppOpsSession.emplace(
104 ValidatedAttributionSourceState::createFromTrustedSource(mAttr), mOps,
105 [this](bool x) { dataDeliveryCb(x); }, AppOpsTestFacade{});
106 }
107
108 // For verification of delivered callbacks
109 // vector<bool> since it's a test
110 std::vector<bool> mDeliveredCbs;
111 std::optional<AppOpsSession<AppOpsTestFacade>> mAppOpsSession;
112 };
113
TEST_F(AppOpsSessionTests,beginDeliveryRequest_Allowed)114 TEST_F(AppOpsSessionTests, beginDeliveryRequest_Allowed) {
115 facadeSetAllowed(true);
116 initSession();
117 EXPECT_TRUE(mAppOpsSession->beginDeliveryRequest());
118 EXPECT_EQ(facadeGetRunning(), 1);
119
120 EXPECT_THAT(mDeliveredCbs, IsEmpty());
121 }
122
TEST_F(AppOpsSessionTests,beginDeliveryRequest_Denied)123 TEST_F(AppOpsSessionTests, beginDeliveryRequest_Denied) {
124 facadeSetAllowed(false);
125 initSession();
126 EXPECT_FALSE(mAppOpsSession->beginDeliveryRequest());
127 EXPECT_EQ(facadeGetRunning(), 0);
128
129 EXPECT_THAT(mDeliveredCbs, IsEmpty());
130 }
131
TEST_F(AppOpsSessionTests,endDeliveryRequest_Ongoing)132 TEST_F(AppOpsSessionTests, endDeliveryRequest_Ongoing) {
133 facadeSetAllowed(true);
134 initSession();
135 EXPECT_TRUE(mAppOpsSession->beginDeliveryRequest());
136 EXPECT_EQ(facadeGetRunning(), 1);
137 mAppOpsSession->endDeliveryRequest();
138 EXPECT_EQ(facadeGetRunning(), 0);
139
140 EXPECT_THAT(mDeliveredCbs, IsEmpty());
141 }
142
TEST_F(AppOpsSessionTests,endDeliveryRequest_Paused)143 TEST_F(AppOpsSessionTests, endDeliveryRequest_Paused) {
144 facadeSetAllowed(false);
145 initSession();
146 EXPECT_FALSE(mAppOpsSession->beginDeliveryRequest());
147 EXPECT_EQ(facadeGetRunning(), 0);
148 mAppOpsSession->endDeliveryRequest();
149 EXPECT_EQ(facadeGetRunning(), 0);
150
151 EXPECT_THAT(mDeliveredCbs, IsEmpty());
152 }
153
TEST_F(AppOpsSessionTests,endDeliveryRequest_PausedByCb)154 TEST_F(AppOpsSessionTests, endDeliveryRequest_PausedByCb) {
155 facadeSetAllowed(true);
156 initSession();
157 EXPECT_TRUE(mAppOpsSession->beginDeliveryRequest());
158 EXPECT_EQ(facadeGetRunning(), 1);
159 facadeTriggerChange(false);
160 EXPECT_EQ(facadeGetRunning(), 0);
161
162 mAppOpsSession->endDeliveryRequest();
163 EXPECT_EQ(facadeGetRunning(), 0);
164 }
165
TEST_F(AppOpsSessionTests,onPermittedFalse_Ongoing_Change)166 TEST_F(AppOpsSessionTests, onPermittedFalse_Ongoing_Change) {
167 facadeSetAllowed(true);
168 initSession();
169 EXPECT_TRUE(mAppOpsSession->beginDeliveryRequest());
170 EXPECT_EQ(facadeGetRunning(), 1);
171 facadeTriggerChange(false);
172 EXPECT_EQ(facadeGetRunning(), 0);
173 EXPECT_THAT(mDeliveredCbs, ElementsAreArray({false}));
174 }
175
TEST_F(AppOpsSessionTests,onPermittedTrue_Ongoing_Change)176 TEST_F(AppOpsSessionTests, onPermittedTrue_Ongoing_Change) {
177 facadeSetAllowed(false);
178 initSession();
179 EXPECT_FALSE(mAppOpsSession->beginDeliveryRequest());
180 EXPECT_EQ(facadeGetRunning(), 0);
181 facadeTriggerChange(true);
182 EXPECT_EQ(facadeGetRunning(), 1);
183 EXPECT_THAT(mDeliveredCbs, ElementsAreArray({true}));
184 }
185
TEST_F(AppOpsSessionTests,onPermittedTrue_Ongoing_Change_Spurious)186 TEST_F(AppOpsSessionTests, onPermittedTrue_Ongoing_Change_Spurious) {
187 facadeSetAllowed(false);
188 initSession();
189 EXPECT_FALSE(mAppOpsSession->beginDeliveryRequest());
190 EXPECT_EQ(facadeGetRunning(), 0);
191 facadeTriggerSpuriousChange(true);
192 EXPECT_EQ(facadeGetRunning(), 0);
193 EXPECT_THAT(mDeliveredCbs, IsEmpty());
194 }
195
TEST_F(AppOpsSessionTests,onPermittedFalse_Ongoing_Same)196 TEST_F(AppOpsSessionTests, onPermittedFalse_Ongoing_Same) {
197 facadeSetAllowed(false);
198 initSession();
199 EXPECT_FALSE(mAppOpsSession->beginDeliveryRequest());
200 EXPECT_EQ(facadeGetRunning(), 0);
201 facadeTriggerSpuriousChange(false);
202 EXPECT_EQ(facadeGetRunning(), 0);
203
204 EXPECT_THAT(mDeliveredCbs, IsEmpty());
205 }
206
TEST_F(AppOpsSessionTests,onPermittedTrue_Ongoing_Same)207 TEST_F(AppOpsSessionTests, onPermittedTrue_Ongoing_Same) {
208 facadeSetAllowed(true);
209 initSession();
210 EXPECT_TRUE(mAppOpsSession->beginDeliveryRequest());
211 EXPECT_EQ(facadeGetRunning(), 1);
212 facadeTriggerSpuriousChange(true);
213 EXPECT_EQ(facadeGetRunning(), 1);
214
215 EXPECT_THAT(mDeliveredCbs, IsEmpty());
216 }
217
TEST_F(AppOpsSessionTests,onPermittedFalse_Paused_Change)218 TEST_F(AppOpsSessionTests, onPermittedFalse_Paused_Change) {
219 facadeSetAllowed(true);
220 initSession();
221 EXPECT_TRUE(mAppOpsSession->beginDeliveryRequest());
222 mAppOpsSession->endDeliveryRequest();
223
224 EXPECT_EQ(facadeGetRunning(), 0);
225 facadeTriggerChange(false);
226 EXPECT_EQ(facadeGetRunning(), 0);
227 EXPECT_THAT(mDeliveredCbs, IsEmpty());
228 }
229
TEST_F(AppOpsSessionTests,onPermittedTrue_Paused_Change)230 TEST_F(AppOpsSessionTests, onPermittedTrue_Paused_Change) {
231 facadeSetAllowed(false);
232 initSession();
233 EXPECT_FALSE(mAppOpsSession->beginDeliveryRequest());
234 mAppOpsSession->endDeliveryRequest();
235
236 facadeTriggerChange(true);
237 EXPECT_EQ(facadeGetRunning(), 0);
238 EXPECT_THAT(mDeliveredCbs, IsEmpty());
239 }
240
TEST_F(AppOpsSessionTests,dtor_Running)241 TEST_F(AppOpsSessionTests, dtor_Running) {
242 facadeSetAllowed(true);
243 initSession();
244 EXPECT_TRUE(mAppOpsSession->beginDeliveryRequest());
245 EXPECT_EQ(facadeGetRunning(), 1);
246
247 // call dtor
248 mAppOpsSession.reset();
249 EXPECT_EQ(facadeGetRunning(), 0);
250 }
251
TEST_F(AppOpsSessionTests,dtor_NotRunning)252 TEST_F(AppOpsSessionTests, dtor_NotRunning) {
253 facadeSetAllowed(false);
254 initSession();
255 EXPECT_FALSE(mAppOpsSession->beginDeliveryRequest());
256 EXPECT_EQ(facadeGetRunning(), 0);
257
258 // call dtor
259 mAppOpsSession.reset();
260 EXPECT_EQ(facadeGetRunning(), 0);
261 }
262