• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023, 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 <binder/ProcessState.h>
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20 #include <gtest_matchers.h>
21 #include <stats_subscription.h>
22 #include <stdint.h>
23 #include <utils/Looper.h>
24 
25 #include <chrono>
26 #include <string>
27 #include <thread>
28 #include <vector>
29 
30 #include "packages/modules/StatsD/statsd/src/shell/shell_config.pb.h"
31 #include "packages/modules/StatsD/statsd/src/shell/shell_data.pb.h"
32 #include "statslog_statsdtest.h"
33 
34 #ifdef __ANDROID__
35 
36 using namespace testing;
37 using android::Looper;
38 using android::ProcessState;
39 using android::sp;
40 using android::os::statsd::Atom;
41 using android::os::statsd::ShellData;
42 using android::os::statsd::ShellSubscription;
43 using android::os::statsd::TestAtomReported_State_OFF;
44 using android::os::statsd::TrainExperimentIds;
45 using android::os::statsd::util::BytesField;
46 using android::os::statsd::util::SCREEN_BRIGHTNESS_CHANGED;
47 using android::os::statsd::util::stats_write;
48 using android::os::statsd::util::TEST_ATOM_REPORTED;
49 using android::os::statsd::util::TEST_ATOM_REPORTED__REPEATED_ENUM_FIELD__OFF;
50 using std::string;
51 using std::vector;
52 using std::this_thread::sleep_for;
53 
54 namespace {
55 
56 class SubscriptionTest : public Test {
57 public:
SubscriptionTest()58     SubscriptionTest() : looper(Looper::prepare(/*opts=*/0)) {
59         const TestInfo* const test_info = UnitTest::GetInstance()->current_test_info();
60         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
61 
62         *trainExpIds.mutable_experiment_id() = {expIds.begin(), expIds.end()};
63         trainExpIds.SerializeToString(&trainExpIdsBytes);
64     }
65 
~SubscriptionTest()66     ~SubscriptionTest() {
67         const TestInfo* const test_info = UnitTest::GetInstance()->current_test_info();
68         ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
69     }
70 
71 protected:
SetUp()72     void SetUp() override {
73         // Start the Binder thread pool.
74         ProcessState::self()->startThreadPool();
75     }
76 
TearDown()77     void TearDown() {
78         // Clear any dangling subscriptions from statsd.
79         if (__builtin_available(android __STATSD_SUBS_MIN_API__, *)) {
80             AStatsManager_removeSubscription(subId);
81         }
82     }
83 
LogTestAtomReported(int32_t intFieldValue)84     void LogTestAtomReported(int32_t intFieldValue) {
85         const BytesField bytesField(trainExpIdsBytes.data(), trainExpIdsBytes.size());
86         stats_write(TEST_ATOM_REPORTED, uids.data(), uids.size(), tags, intFieldValue,
87                     /*long_field=*/2LL, /*float_field=*/3.0F,
88                     /*string_field=*/string1.c_str(),
89                     /*boolean_field=*/false, /*state=*/TEST_ATOM_REPORTED__REPEATED_ENUM_FIELD__OFF,
90                     bytesField, repeatedInts, repeatedLongs, repeatedFloats, repeatedStrings,
91                     &(repeatedBool[0]), /*repeatedBoolSize=*/2, repeatedEnums);
92     }
93 
94     int32_t subId;
95 
96     // TestAtomReported fields.
97     const vector<int32_t> uids = {1};
98     const string tag = "test";
99     const vector<char const*> tags = {tag.c_str()};
100 
101     // 100 int64s for the MODE_BYTES field to push atom size to over 1K.
102     const vector<int64_t> expIds = vector<int64_t>(100, INT64_MAX);
103 
104     const vector<int32_t> repeatedInts{1};
105     const vector<int64_t> repeatedLongs{2LL};
106     const vector<float> repeatedFloats{3.0F};
107     const string string1 = "ABC";
108     const vector<char const*> repeatedStrings = {string1.c_str()};
109     const bool repeatedBool[2] = {false, true};
110     const vector<int32_t> repeatedEnums = {TEST_ATOM_REPORTED__REPEATED_ENUM_FIELD__OFF};
111     TrainExperimentIds trainExpIds;
112     string trainExpIdsBytes;
113 
114 private:
115     sp<Looper> looper;
116 };
117 
118 // Stores arguments passed in subscription callback.
119 struct CallbackData {
120     int32_t subId;
121     AStatsManager_SubscriptionCallbackReason reason;
122     vector<uint8_t> payload;
123     int count;  // Stores number of times the callback is invoked.
124 };
125 
callback(int32_t subscription_id,AStatsManager_SubscriptionCallbackReason reason,uint8_t * _Nonnull payload,size_t num_bytes,void * _Nullable cookie)126 static void callback(int32_t subscription_id, AStatsManager_SubscriptionCallbackReason reason,
127                      uint8_t* _Nonnull payload, size_t num_bytes, void* _Nullable cookie) {
128     CallbackData* data = static_cast<CallbackData*>(cookie);
129     data->subId = subscription_id;
130     data->reason = reason;
131     data->payload.assign(payload, payload + num_bytes);
132     data->count++;
133 }
134 
135 constexpr static int WAIT_MS = 500;
136 
TEST_F(SubscriptionTest,TestSubscription)137 TEST_F(SubscriptionTest, TestSubscription) {
138     if (__builtin_available(android __STATSD_SUBS_MIN_API__, *)) {
139         ShellSubscription config;
140         config.add_pushed()->set_atom_id(TEST_ATOM_REPORTED);
141         config.add_pushed()->set_atom_id(SCREEN_BRIGHTNESS_CHANGED);
142 
143         string configBytes;
144         config.SerializeToString(&configBytes);
145 
146         CallbackData callbackData{/*subId=*/0,
147                                   ASTATSMANAGER_SUBSCRIPTION_CALLBACK_REASON_SUBSCRIPTION_ENDED,
148                                   /*payload=*/{},
149                                   /*count=*/0};
150 
151         // Add subscription.
152         subId = AStatsManager_addSubscription(reinterpret_cast<const uint8_t*>(configBytes.data()),
153                                               configBytes.size(), &callback, &callbackData);
154         ASSERT_GT(subId, 0);
155         sleep_for(std::chrono::milliseconds(WAIT_MS));
156 
157         // Log events without exceeding statsd cache.
158         stats_write(SCREEN_BRIGHTNESS_CHANGED, 100);
159         LogTestAtomReported(1);
160         sleep_for(std::chrono::milliseconds(WAIT_MS));
161 
162         // Verify no callback occurred yet.
163         EXPECT_EQ(callbackData.subId, 0);
164         EXPECT_EQ(callbackData.reason,
165                   ASTATSMANAGER_SUBSCRIPTION_CALLBACK_REASON_SUBSCRIPTION_ENDED);
166         EXPECT_EQ(callbackData.count, 0);
167         ASSERT_TRUE(callbackData.payload.empty());
168 
169         // Log another TestAtomReported to overflow cache.
170         LogTestAtomReported(2);
171         sleep_for(std::chrono::milliseconds(WAIT_MS));
172 
173         // Verify callback occurred.
174         EXPECT_EQ(callbackData.subId, subId);
175         EXPECT_EQ(callbackData.reason, ASTATSMANAGER_SUBSCRIPTION_CALLBACK_REASON_STATSD_INITIATED);
176         EXPECT_EQ(callbackData.count, 1);
177         ASSERT_GT(callbackData.payload.size(), 0);
178 
179         ShellData actualShellData;
180         ASSERT_TRUE(actualShellData.ParseFromArray(callbackData.payload.data(),
181                                                    callbackData.payload.size()));
182 
183         ASSERT_GE(actualShellData.elapsed_timestamp_nanos_size(), 3);
184         EXPECT_THAT(actualShellData.elapsed_timestamp_nanos(), Each(Gt(0LL)));
185 
186         ASSERT_GE(actualShellData.atom_size(), 3);
187 
188         // Verify atom 1.
189         Atom expectedAtom;
190         expectedAtom.mutable_screen_brightness_changed()->set_level(100);
191         EXPECT_THAT(actualShellData.atom(0), EqAtom(expectedAtom));
192 
193         // Verify atom 2.
194         expectedAtom.Clear();
195         auto* testAtomReported = expectedAtom.mutable_test_atom_reported();
196         auto* attributionNode = testAtomReported->add_attribution_node();
197         attributionNode->set_uid(uids[0]);
198         attributionNode->set_tag(tag);
199         testAtomReported->set_int_field(1);
200         testAtomReported->set_long_field(2LL);
201         testAtomReported->set_float_field(3.0F);
202         testAtomReported->set_string_field(string1);
203         testAtomReported->set_boolean_field(false);
204         testAtomReported->set_state(TestAtomReported_State_OFF);
205         *testAtomReported->mutable_bytes_field() = trainExpIds;
206         *testAtomReported->mutable_repeated_int_field() = {repeatedInts.begin(),
207                                                            repeatedInts.end()};
208         *testAtomReported->mutable_repeated_long_field() = {repeatedLongs.begin(),
209                                                             repeatedLongs.end()};
210         *testAtomReported->mutable_repeated_float_field() = {repeatedFloats.begin(),
211                                                              repeatedFloats.end()};
212         *testAtomReported->mutable_repeated_string_field() = {repeatedStrings.begin(),
213                                                               repeatedStrings.end()};
214         *testAtomReported->mutable_repeated_boolean_field() = {&repeatedBool[0],
215                                                                &repeatedBool[0] + 2};
216         *testAtomReported->mutable_repeated_enum_field() = {repeatedEnums.begin(),
217                                                             repeatedEnums.end()};
218         EXPECT_THAT(actualShellData.atom(1), EqAtom(expectedAtom));
219 
220         // Verify atom 3.
221         testAtomReported->set_int_field(2);
222         EXPECT_THAT(actualShellData.atom(2), EqAtom(expectedAtom));
223 
224         // Log another ScreenBrightnessChanged atom. No callback should occur.
225         stats_write(SCREEN_BRIGHTNESS_CHANGED, 99);
226         sleep_for(std::chrono::milliseconds(WAIT_MS));
227         EXPECT_EQ(callbackData.count, 1);
228 
229         // Flush subscription. Callback should occur.
230         AStatsManager_flushSubscription(subId);
231         sleep_for(std::chrono::milliseconds(WAIT_MS));
232 
233         EXPECT_EQ(callbackData.subId, subId);
234         EXPECT_EQ(callbackData.reason, ASTATSMANAGER_SUBSCRIPTION_CALLBACK_REASON_FLUSH_REQUESTED);
235         EXPECT_EQ(callbackData.count, 2);
236         ASSERT_GT(callbackData.payload.size(), 0);
237 
238         ASSERT_TRUE(actualShellData.ParseFromArray(callbackData.payload.data(),
239                                                    callbackData.payload.size()));
240 
241         ASSERT_GE(actualShellData.elapsed_timestamp_nanos_size(), 1);
242         EXPECT_THAT(actualShellData.elapsed_timestamp_nanos(), Each(Gt(0LL)));
243 
244         ASSERT_GE(actualShellData.atom_size(), 1);
245 
246         // Verify atom 1.
247         expectedAtom.Clear();
248         expectedAtom.mutable_screen_brightness_changed()->set_level(99);
249         EXPECT_THAT(actualShellData.atom(0), EqAtom(expectedAtom));
250 
251         // Log another ScreenBrightnessChanged atom. No callback should occur.
252         stats_write(SCREEN_BRIGHTNESS_CHANGED, 98);
253         sleep_for(std::chrono::milliseconds(WAIT_MS));
254         EXPECT_EQ(callbackData.count, 2);
255 
256         // Trigger callback through cache timeout.
257         // Two 500 ms sleeps have occurred already so the total sleep is 71000 ms since last
258         // callback invocation.
259         sleep_for(std::chrono::milliseconds(70'000));
260         EXPECT_EQ(callbackData.subId, subId);
261         EXPECT_EQ(callbackData.reason, ASTATSMANAGER_SUBSCRIPTION_CALLBACK_REASON_STATSD_INITIATED);
262         EXPECT_EQ(callbackData.count, 3);
263         ASSERT_GT(callbackData.payload.size(), 0);
264 
265         ASSERT_TRUE(actualShellData.ParseFromArray(callbackData.payload.data(),
266                                                    callbackData.payload.size()));
267 
268         ASSERT_GE(actualShellData.elapsed_timestamp_nanos_size(), 1);
269         EXPECT_THAT(actualShellData.elapsed_timestamp_nanos(), Each(Gt(0LL)));
270 
271         ASSERT_GE(actualShellData.atom_size(), 1);
272 
273         // Verify atom 1.
274         expectedAtom.Clear();
275         expectedAtom.mutable_screen_brightness_changed()->set_level(98);
276         EXPECT_THAT(actualShellData.atom(0), EqAtom(expectedAtom));
277 
278         // Log another ScreenBrightnessChanged atom. No callback should occur.
279         stats_write(SCREEN_BRIGHTNESS_CHANGED, 97);
280         sleep_for(std::chrono::milliseconds(WAIT_MS));
281         EXPECT_EQ(callbackData.count, 3);
282 
283         // End subscription. Final callback should occur.
284         AStatsManager_removeSubscription(subId);
285         sleep_for(std::chrono::milliseconds(WAIT_MS));
286 
287         EXPECT_EQ(callbackData.subId, subId);
288         EXPECT_EQ(callbackData.reason,
289                   ASTATSMANAGER_SUBSCRIPTION_CALLBACK_REASON_SUBSCRIPTION_ENDED);
290         EXPECT_EQ(callbackData.count, 4);
291         ASSERT_GT(callbackData.payload.size(), 0);
292 
293         ASSERT_TRUE(actualShellData.ParseFromArray(callbackData.payload.data(),
294                                                    callbackData.payload.size()));
295 
296         ASSERT_GE(actualShellData.elapsed_timestamp_nanos_size(), 1);
297         EXPECT_THAT(actualShellData.elapsed_timestamp_nanos(), Each(Gt(0LL)));
298 
299         ASSERT_GE(actualShellData.atom_size(), 1);
300 
301         // Verify atom 1.
302         expectedAtom.Clear();
303         expectedAtom.mutable_screen_brightness_changed()->set_level(97);
304         EXPECT_THAT(actualShellData.atom(0), EqAtom(expectedAtom));
305     } else {
306         GTEST_SKIP();
307     }
308 }
309 
310 }  // namespace
311 
312 #else
313 GTEST_LOG_(INFO) << "This test does nothing.\n";
314 #endif
315