1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/shell/ShellSubscriber.h"
16
17 #include <aidl/android/os/StatsSubscriptionCallbackReason.h>
18 #include <gtest/gtest.h>
19 #include <stdio.h>
20 #include <unistd.h>
21
22 #include <optional>
23 #include <vector>
24
25 #include "frameworks/proto_logging/stats/atoms.pb.h"
26 #include "gtest_matchers.h"
27 #include "src/guardrail/StatsdStats.h"
28 #include "src/shell/shell_config.pb.h"
29 #include "src/shell/shell_data.pb.h"
30 #include "src/stats_log.pb.h"
31 #include "stats_event.h"
32 #include "statslog_statsdtest.h"
33 #include "tests/metrics/metrics_test_helper.h"
34 #include "tests/statsd_test_util.h"
35
36 using ::aidl::android::os::StatsSubscriptionCallbackReason;
37 using android::sp;
38 using android::os::statsd::TestAtomReported;
39 using android::os::statsd::TrainExperimentIds;
40 using android::os::statsd::util::BytesField;
41 using android::os::statsd::util::CPU_ACTIVE_TIME;
42 using android::os::statsd::util::PHONE_SIGNAL_STRENGTH_CHANGED;
43 using android::os::statsd::util::PLUGGED_STATE_CHANGED;
44 using android::os::statsd::util::SCREEN_STATE_CHANGED;
45 using android::os::statsd::util::TEST_ATOM_REPORTED;
46 using std::vector;
47 using testing::_;
48 using testing::A;
49 using testing::AtMost;
50 using testing::ByMove;
51 using testing::DoAll;
52 using testing::InSequence;
53 using testing::Invoke;
54 using testing::MockFunction;
55 using testing::NaggyMock;
56 using testing::NiceMock;
57 using testing::Return;
58 using testing::SaveArg;
59 using testing::SetArgPointee;
60 using testing::StrictMock;
61
62 namespace android {
63 namespace os {
64 namespace statsd {
65
66 #ifdef __ANDROID__
67
68 namespace {
69
70 int kUid1 = 1000;
71 int kUid2 = 2000;
72
73 int kCpuTime1 = 100;
74 int kCpuTime2 = 200;
75
76 int64_t kCpuActiveTimeEventTimestampNs = 1111L;
77
78 // Number of clients running simultaneously
79
80 // Just a single client
81 const int kSingleClient = 1;
82 // One more client than allowed binder threads
83 const int kNumClients = 11;
84
85 // Utility to make an expected pulled atom shell data
getExpectedPulledData()86 ShellData getExpectedPulledData() {
87 ShellData shellData;
88 auto* atom1 = shellData.add_atom()->mutable_cpu_active_time();
89 atom1->set_uid(kUid1);
90 atom1->set_time_millis(kCpuTime1);
91 shellData.add_elapsed_timestamp_nanos(kCpuActiveTimeEventTimestampNs);
92
93 auto* atom2 = shellData.add_atom()->mutable_cpu_active_time();
94 atom2->set_uid(kUid2);
95 atom2->set_time_millis(kCpuTime2);
96 shellData.add_elapsed_timestamp_nanos(kCpuActiveTimeEventTimestampNs);
97
98 return shellData;
99 }
100
101 // Utility to make a pulled atom Shell Config
getPulledConfig()102 ShellSubscription getPulledConfig() {
103 ShellSubscription config;
104 auto* pull_config = config.add_pulled();
105 pull_config->mutable_matcher()->set_atom_id(CPU_ACTIVE_TIME);
106 pull_config->set_freq_millis(2000);
107 return config;
108 }
109
110 // Utility to adjust CPU time for pulled events
makeCpuActiveTimeAtom(int32_t uid,int64_t timeMillis)111 shared_ptr<LogEvent> makeCpuActiveTimeAtom(int32_t uid, int64_t timeMillis) {
112 AStatsEvent* statsEvent = AStatsEvent_obtain();
113 AStatsEvent_setAtomId(statsEvent, CPU_ACTIVE_TIME);
114 AStatsEvent_overwriteTimestamp(statsEvent, kCpuActiveTimeEventTimestampNs);
115 AStatsEvent_writeInt32(statsEvent, uid);
116 AStatsEvent_writeInt64(statsEvent, timeMillis);
117
118 std::shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
119 parseStatsEventToLogEvent(statsEvent, logEvent.get());
120 return logEvent;
121 }
122
123 // Utility to create pushed atom LogEvents
getPushedEvents()124 vector<std::shared_ptr<LogEvent>> getPushedEvents() {
125 vector<std::shared_ptr<LogEvent>> pushedList;
126 // Create the LogEvent from an AStatsEvent
127 std::unique_ptr<LogEvent> logEvent1 = CreateScreenStateChangedEvent(
128 1000 /*timestamp*/, ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
129 std::unique_ptr<LogEvent> logEvent2 = CreateScreenStateChangedEvent(
130 2000 /*timestamp*/, ::android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
131 std::unique_ptr<LogEvent> logEvent3 = CreateBatteryStateChangedEvent(
132 3000 /*timestamp*/, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
133 std::unique_ptr<LogEvent> logEvent4 = CreateBatteryStateChangedEvent(
134 4000 /*timestamp*/, BatteryPluggedStateEnum::BATTERY_PLUGGED_NONE);
135 pushedList.push_back(std::move(logEvent1));
136 pushedList.push_back(std::move(logEvent2));
137 pushedList.push_back(std::move(logEvent3));
138 pushedList.push_back(std::move(logEvent4));
139 return pushedList;
140 }
141
142 // Utility to read & return ShellData proto, skipping heartbeats.
readData(int fd)143 static ShellData readData(int fd) {
144 ssize_t dataSize = 0;
145 while (dataSize == 0) {
146 read(fd, &dataSize, sizeof(dataSize));
147 }
148 // Read that much data in proto binary format.
149 vector<uint8_t> dataBuffer(dataSize);
150 EXPECT_EQ((int)dataSize, read(fd, dataBuffer.data(), dataSize));
151
152 // Make sure the received bytes can be parsed to an atom.
153 ShellData receivedAtom;
154 EXPECT_TRUE(receivedAtom.ParseFromArray(dataBuffer.data(), dataSize) != 0);
155 return receivedAtom;
156 }
157
runShellTest(ShellSubscription config,sp<MockUidMap> uidMap,sp<MockStatsPullerManager> pullerManager,const vector<std::shared_ptr<LogEvent>> & pushedEvents,const vector<ShellData> & expectedData,int numClients)158 void runShellTest(ShellSubscription config, sp<MockUidMap> uidMap,
159 sp<MockStatsPullerManager> pullerManager,
160 const vector<std::shared_ptr<LogEvent>>& pushedEvents,
161 const vector<ShellData>& expectedData, int numClients) {
162 sp<ShellSubscriber> shellManager =
163 new ShellSubscriber(uidMap, pullerManager, std::make_shared<LogEventFilter>());
164
165 size_t bufferSize = config.ByteSize();
166 vector<uint8_t> buffer(bufferSize);
167 config.SerializeToArray(&buffer[0], bufferSize);
168
169 int fds_configs[numClients][2];
170 int fds_datas[numClients][2];
171 for (int i = 0; i < numClients; i++) {
172 // set up 2 pipes for read/write config and data
173 ASSERT_EQ(0, pipe2(fds_configs[i], O_CLOEXEC));
174 ASSERT_EQ(0, pipe2(fds_datas[i], O_CLOEXEC));
175
176 // write the config to pipe, first write size of the config
177 write(fds_configs[i][1], &bufferSize, sizeof(bufferSize));
178 // then write config itself
179 write(fds_configs[i][1], buffer.data(), bufferSize);
180 close(fds_configs[i][1]);
181
182 shellManager->startNewSubscription(fds_configs[i][0], fds_datas[i][1], /*timeoutSec=*/-1);
183 close(fds_configs[i][0]);
184 close(fds_datas[i][1]);
185 }
186
187 // send a log event that matches the config.
188 for (const auto& event : pushedEvents) {
189 shellManager->onLogEvent(*event);
190 }
191
192 for (int i = 0; i < numClients; i++) {
193 vector<ShellData> actualData;
194 for (int j = 1; j <= expectedData.size(); j++) {
195 actualData.push_back(readData(fds_datas[i][0]));
196 }
197
198 EXPECT_THAT(expectedData, UnorderedPointwise(EqShellData(), actualData));
199 }
200
201 // Not closing fds_datas[i][0] because this causes writes within ShellSubscriberClient to hang
202 }
203
createTestAtomReportedEvent(const uint64_t timestampNs,const int32_t intFieldValue,const vector<int64_t> & expIds)204 unique_ptr<LogEvent> createTestAtomReportedEvent(const uint64_t timestampNs,
205 const int32_t intFieldValue,
206 const vector<int64_t>& expIds) {
207 TrainExperimentIds trainExpIds;
208 *trainExpIds.mutable_experiment_id() = {expIds.begin(), expIds.end()};
209 const vector<uint8_t> trainExpIdsBytes = protoToBytes(trainExpIds);
210 return CreateTestAtomReportedEvent(
211 timestampNs, /* attributionUids */ {1001},
212 /* attributionTags */ {"app1"}, intFieldValue, /*longField */ 0LL,
213 /* floatField */ 0.0f,
214 /* stringField */ "abc", /* boolField */ false, TestAtomReported::OFF, trainExpIdsBytes,
215 /* repeatedIntField */ {}, /* repeatedLongField */ {}, /* repeatedFloatField */ {},
216 /* repeatedStringField */ {}, /* repeatedBoolField */ {},
217 /* repeatedBoolFieldLength */ 0, /* repeatedEnumField */ {});
218 }
219
createTestAtomReportedProto(const int32_t intFieldValue,const vector<int64_t> & expIds)220 TestAtomReported createTestAtomReportedProto(const int32_t intFieldValue,
221 const vector<int64_t>& expIds) {
222 TestAtomReported t;
223 auto* attributionNode = t.add_attribution_node();
224 attributionNode->set_uid(1001);
225 attributionNode->set_tag("app"); // String transformation removes trailing digits.
226 t.set_int_field(intFieldValue);
227 t.set_long_field(0);
228 t.set_float_field(0.0f);
229 t.set_string_field("abc");
230 t.set_boolean_field(false);
231 t.set_state(TestAtomReported_State_OFF);
232 *t.mutable_bytes_field()->mutable_experiment_id() = {expIds.begin(), expIds.end()};
233 return t;
234 }
235
236 class ShellSubscriberCallbackTest : public ::testing::Test {
237 protected:
ShellSubscriberCallbackTest()238 ShellSubscriberCallbackTest()
239 : uidMap(new NaggyMock<MockUidMap>()),
240 pullerManager(new StrictMock<MockStatsPullerManager>()),
241 mockLogEventFilter(std::make_shared<MockLogEventFilter>()),
242 shellSubscriber(uidMap, pullerManager, mockLogEventFilter),
243 callback(SharedRefBase::make<StrictMock<MockStatsSubscriptionCallback>>()),
244 reason(nullopt) {
245 }
246
SetUp()247 void SetUp() override {
248 // Save callback arguments when it is invoked.
249 ON_CALL(*callback, onSubscriptionData(_, _))
250 .WillByDefault(DoAll(SaveArg<0>(&reason), SaveArg<1>(&payload),
251 [] { return Status::ok(); }));
252
253 ShellSubscription config;
254 config.add_pushed()->set_atom_id(TEST_ATOM_REPORTED);
255 FieldValueMatcher* fvm = config.mutable_pushed(0)->add_field_value_matcher();
256 fvm->set_field(1); // attribution_chain
257 fvm->set_position(Position::FIRST);
258 fvm = fvm->mutable_matches_tuple()->add_field_value_matcher();
259 fvm->set_field(2); // tag field
260 fvm->mutable_replace_string()->set_regex(
261 R"([0-9]+$)"); // match trailing digits, example "42" in "foo42".
262 fvm->mutable_replace_string()->set_replacement("");
263
264 config.add_pushed()->set_atom_id(SCREEN_STATE_CHANGED);
265 config.add_pushed()->set_atom_id(PHONE_SIGNAL_STRENGTH_CHANGED);
266 configBytes = protoToBytes(config);
267
268 StatsdStats::getInstance().reset();
269
270 // Expect empty call from the shellSubscriber destructor
271 // and may be one additional call during unsubscribe if subscription was active.
272 // Putting this here because newer EXPECT_CALL takes precedence over an older one.
273 LogEventFilter::AtomIdSet tagIds;
274 EXPECT_CALL(*mockLogEventFilter, setAtomIds(tagIds, &shellSubscriber)).Times(AtMost(2));
275
276 // Catch callback invocation from uninsteresting unsubscribe call.
277 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(AtMost(1));
278 }
279
TearDown()280 void TearDown() override {
281 shellSubscriber.unsubscribe(callback);
282 StatsdStats::getInstance().reset();
283 }
284
285 sp<MockUidMap> uidMap;
286 sp<MockStatsPullerManager> pullerManager;
287 std::shared_ptr<MockLogEventFilter> mockLogEventFilter;
288 ShellSubscriber shellSubscriber;
289 std::shared_ptr<MockStatsSubscriptionCallback> callback;
290 vector<uint8_t> configBytes;
291
292 // Capture callback arguments.
293 std::optional<StatsSubscriptionCallbackReason> reason;
294 vector<uint8_t> payload;
295 };
296
297 class ShellSubscriberCallbackPulledTest : public ShellSubscriberCallbackTest {
298 protected:
SetUp()299 void SetUp() override {
300 ShellSubscriberCallbackTest::SetUp();
301
302 const vector<int32_t> uids{AID_SYSTEM};
303 const vector<std::shared_ptr<LogEvent>> pulledData{
304 makeCpuActiveTimeAtom(/*uid=*/kUid1, /*timeMillis=*/kCpuTime1),
305 makeCpuActiveTimeAtom(/*uid=*/kUid2, /*timeMillis=*/kCpuTime2)};
306 ON_CALL(*pullerManager, Pull(CPU_ACTIVE_TIME, uids, _, _))
307 .WillByDefault(DoAll(SetArgPointee<3>(pulledData), Return(true)));
308
309 configBytes = protoToBytes(getPulledConfig());
310
311 // Used to call pullAndSendHeartbeatsIfNeeded directly without depending on sleep.
312 shellSubscriberClient = std::move(ShellSubscriberClient::create(
313 configBytes, callback, /* startTimeSec= */ 0, uidMap, pullerManager));
314 }
315
316 unique_ptr<ShellSubscriberClient> shellSubscriberClient;
317 };
318
CreateAtomIdSetFromShellSubscriptionBytes(const vector<uint8_t> & bytes)319 LogEventFilter::AtomIdSet CreateAtomIdSetFromShellSubscriptionBytes(const vector<uint8_t>& bytes) {
320 LogEventFilter::AtomIdSet result;
321
322 ShellSubscription config;
323 config.ParseFromArray(bytes.data(), bytes.size());
324
325 for (int i = 0; i < config.pushed_size(); i++) {
326 const auto& pushed = config.pushed(i);
327 EXPECT_TRUE(pushed.has_atom_id());
328 result.insert(pushed.atom_id());
329 }
330
331 return result;
332 }
333
334 } // namespace
335
TEST_F(ShellSubscriberCallbackTest,testShellSubscriberDestructor)336 TEST_F(ShellSubscriberCallbackTest, testShellSubscriberDestructor) {
337 LogEventFilter::AtomIdSet tagIds;
338 EXPECT_CALL(*mockLogEventFilter, setAtomIds(tagIds, &shellSubscriber)).Times(1);
339 }
340
TEST_F(ShellSubscriberCallbackTest,testAddSubscription)341 TEST_F(ShellSubscriberCallbackTest, testAddSubscription) {
342 EXPECT_CALL(
343 *mockLogEventFilter,
344 setAtomIds(CreateAtomIdSetFromShellSubscriptionBytes(configBytes), &shellSubscriber))
345 .Times(1);
346
347 ASSERT_TRUE(shellSubscriber.startNewSubscription(configBytes, callback));
348
349 auto subscriptionStats = getStatsdStatsReport().subscription_stats();
350
351 ASSERT_EQ(subscriptionStats.per_subscription_stats_size(), 1);
352 auto perSubscriptionStats = subscriptionStats.per_subscription_stats(0);
353 EXPECT_EQ(perSubscriptionStats.pushed_atom_count(), 3);
354 EXPECT_FALSE(perSubscriptionStats.has_pulled_atom_count());
355 EXPECT_GT(perSubscriptionStats.start_time_sec(), 0);
356 EXPECT_EQ(perSubscriptionStats.end_time_sec(), 0);
357 EXPECT_EQ(perSubscriptionStats.flush_count(), 0);
358 }
359
TEST_F(ShellSubscriberCallbackTest,testAddSubscriptionExceedMax)360 TEST_F(ShellSubscriberCallbackTest, testAddSubscriptionExceedMax) {
361 const size_t maxSubs = ShellSubscriber::getMaxSubscriptions();
362 // setAtomIds called with tagIds during subscribe and unsubscribe until the 2nd last
363 // subscription is removed
364 EXPECT_CALL(
365 *mockLogEventFilter,
366 setAtomIds(CreateAtomIdSetFromShellSubscriptionBytes(configBytes), &shellSubscriber))
367 .Times(maxSubs * 2 - 1);
368
369 // setAtomIds called with empty tagIds during last unsubscribe.
370 LogEventFilter::AtomIdSet tagIds;
371 EXPECT_CALL(*mockLogEventFilter, setAtomIds(tagIds, &shellSubscriber))
372 .Times(1)
373 .RetiresOnSaturation();
374
375 vector<uint8_t> results(maxSubs, false);
376
377 std::shared_ptr<MockStatsSubscriptionCallback> callbacks[maxSubs];
378 for (int i = 0; i < maxSubs; i++) {
379 callbacks[i] = SharedRefBase::make<NiceMock<MockStatsSubscriptionCallback>>();
380 ON_CALL(*(callbacks[i]), onSubscriptionData(_, _))
381 .WillByDefault(Return(ByMove(Status::ok())));
382 results[i] = shellSubscriber.startNewSubscription(configBytes, callbacks[i]);
383 }
384
385 // First maxSubs subscriptions should succeed.
386 EXPECT_THAT(results, Each(IsTrue()));
387
388 // Subsequent startNewSubscription should fail.
389 EXPECT_FALSE(shellSubscriber.startNewSubscription(configBytes, callback));
390
391 for (int i = 0; i < maxSubs; i++) {
392 shellSubscriber.unsubscribe(callbacks[i]);
393 }
394 }
395
TEST_F(ShellSubscriberCallbackTest,testPushedEventsAreCached)396 TEST_F(ShellSubscriberCallbackTest, testPushedEventsAreCached) {
397 MockFunction<void(string checkPointName)> check;
398 {
399 // Use InSequence and MockFunction to make onSubscriptionData called 0 times work as
400 // expected by only limiting the scope to until the end of the test body and ignore the
401 // onSubscriptionData EXPECT_CALL in the tearDown().
402 InSequence s;
403
404 // Expect callback to not be invoked until test body has finished executing.
405 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(Exactly(0));
406 EXPECT_CALL(*mockLogEventFilter,
407 setAtomIds(CreateAtomIdSetFromShellSubscriptionBytes(configBytes),
408 &shellSubscriber))
409 .Times(1);
410 EXPECT_CALL(check, Call(""));
411 }
412 shellSubscriber.startNewSubscription(configBytes, callback);
413
414 // Log an event that does NOT invoke the callack.
415 shellSubscriber.onLogEvent(*CreateScreenStateChangedEvent(
416 1000 /*timestamp*/, ::android::view::DisplayStateEnum::DISPLAY_STATE_ON));
417
418 check.Call("");
419 }
420
TEST_F(ShellSubscriberCallbackTest,testOverflowCacheIsFlushed)421 TEST_F(ShellSubscriberCallbackTest, testOverflowCacheIsFlushed) {
422 // Expect callback to be invoked once.
423 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(Exactly(1)).RetiresOnSaturation();
424 EXPECT_CALL(
425 *mockLogEventFilter,
426 setAtomIds(CreateAtomIdSetFromShellSubscriptionBytes(configBytes), &shellSubscriber))
427 .Times(1);
428 shellSubscriber.startNewSubscription(configBytes, callback);
429
430 shellSubscriber.onLogEvent(*CreateScreenStateChangedEvent(
431 1000 /*timestamp*/, ::android::view::DisplayStateEnum::DISPLAY_STATE_ON));
432
433 // Inflate size of TestAtomReported through the MODE_BYTES field.
434 const vector<int64_t> expIds = vector<int64_t>(200, INT64_MAX);
435
436 // This event should trigger cache overflow flush.
437 shellSubscriber.onLogEvent(*createTestAtomReportedEvent(/*timestampNs=*/1100,
438 /*intFieldValue=*/1, expIds));
439
440 EXPECT_THAT(reason, Eq(StatsSubscriptionCallbackReason::STATSD_INITIATED));
441
442 // Get ShellData proto from the bytes payload of the callback.
443 ShellData actualShellData;
444 ASSERT_TRUE(actualShellData.ParseFromArray(payload.data(), payload.size()));
445
446 ShellData expectedShellData;
447 expectedShellData.add_atom()->mutable_screen_state_changed()->set_state(
448 ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
449 *expectedShellData.add_atom()->mutable_test_atom_reported() =
450 createTestAtomReportedProto(/* intFieldValue=*/1, expIds);
451 expectedShellData.add_elapsed_timestamp_nanos(1000);
452 expectedShellData.add_elapsed_timestamp_nanos(1100);
453
454 EXPECT_THAT(actualShellData, EqShellData(expectedShellData));
455
456 auto subscriptionStats = getStatsdStatsReport().subscription_stats();
457 ASSERT_EQ(subscriptionStats.per_subscription_stats_size(), 1);
458 auto perSubscriptionStats = subscriptionStats.per_subscription_stats(0);
459 EXPECT_EQ(perSubscriptionStats.flush_count(), 1);
460 }
461
TEST_F(ShellSubscriberCallbackTest,testFlushTrigger)462 TEST_F(ShellSubscriberCallbackTest, testFlushTrigger) {
463 // Expect callback to be invoked once.
464 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(Exactly(1)).RetiresOnSaturation();
465 EXPECT_CALL(
466 *mockLogEventFilter,
467 setAtomIds(CreateAtomIdSetFromShellSubscriptionBytes(configBytes), &shellSubscriber))
468 .Times(1);
469 shellSubscriber.startNewSubscription(configBytes, callback);
470
471 shellSubscriber.onLogEvent(*CreateScreenStateChangedEvent(
472 1000 /*timestamp*/, ::android::view::DisplayStateEnum::DISPLAY_STATE_ON));
473
474 shellSubscriber.flushSubscription(callback);
475
476 EXPECT_THAT(reason, Eq(StatsSubscriptionCallbackReason::FLUSH_REQUESTED));
477
478 // Get ShellData proto from the bytes payload of the callback.
479 ShellData actualShellData;
480 ASSERT_TRUE(actualShellData.ParseFromArray(payload.data(), payload.size()));
481
482 ShellData expectedShellData;
483 expectedShellData.add_atom()->mutable_screen_state_changed()->set_state(
484 ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
485 expectedShellData.add_elapsed_timestamp_nanos(1000);
486
487 EXPECT_THAT(actualShellData, EqShellData(expectedShellData));
488
489 auto subscriptionStats = getStatsdStatsReport().subscription_stats();
490 ASSERT_EQ(subscriptionStats.per_subscription_stats_size(), 1);
491 auto perSubscriptionStats = subscriptionStats.per_subscription_stats(0);
492 EXPECT_EQ(perSubscriptionStats.flush_count(), 1);
493 }
494
TEST_F(ShellSubscriberCallbackTest,testFlushTriggerEmptyCache)495 TEST_F(ShellSubscriberCallbackTest, testFlushTriggerEmptyCache) {
496 // Expect callback to be invoked once.
497 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(Exactly(1)).RetiresOnSaturation();
498 EXPECT_CALL(
499 *mockLogEventFilter,
500 setAtomIds(CreateAtomIdSetFromShellSubscriptionBytes(configBytes), &shellSubscriber))
501 .Times(1);
502 shellSubscriber.startNewSubscription(configBytes, callback);
503
504 shellSubscriber.flushSubscription(callback);
505
506 EXPECT_THAT(reason, Eq(StatsSubscriptionCallbackReason::FLUSH_REQUESTED));
507
508 // Get ShellData proto from the bytes payload of the callback.
509 ShellData actualShellData;
510 ASSERT_TRUE(actualShellData.ParseFromArray(payload.data(), payload.size()));
511
512 ShellData expectedShellData;
513
514 EXPECT_THAT(actualShellData, EqShellData(expectedShellData));
515
516 auto subscriptionStats = getStatsdStatsReport().subscription_stats();
517 ASSERT_EQ(subscriptionStats.per_subscription_stats_size(), 1);
518 auto perSubscriptionStats = subscriptionStats.per_subscription_stats(0);
519 ASSERT_EQ(perSubscriptionStats.flush_count(), 1);
520 }
521
TEST_F(ShellSubscriberCallbackTest,testUnsubscribe)522 TEST_F(ShellSubscriberCallbackTest, testUnsubscribe) {
523 // Expect callback to be invoked once.
524 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(Exactly(1));
525 Expectation newSubcriptionEvent =
526 EXPECT_CALL(*mockLogEventFilter,
527 setAtomIds(CreateAtomIdSetFromShellSubscriptionBytes(configBytes),
528 &shellSubscriber))
529 .Times(1);
530
531 // setAtomIds called with no atoms on unsubscribe.
532 LogEventFilter::AtomIdSet idSetEmpty;
533 EXPECT_CALL(*mockLogEventFilter, setAtomIds(idSetEmpty, &shellSubscriber))
534 .Times(1)
535 .After(newSubcriptionEvent)
536 .RetiresOnSaturation();
537
538 shellSubscriber.startNewSubscription(configBytes, callback);
539
540 shellSubscriber.onLogEvent(*CreateScreenStateChangedEvent(
541 1000 /*timestamp*/, ::android::view::DisplayStateEnum::DISPLAY_STATE_ON));
542
543 shellSubscriber.unsubscribe(callback);
544
545 EXPECT_THAT(reason, Eq(StatsSubscriptionCallbackReason::SUBSCRIPTION_ENDED));
546
547 // Get ShellData proto from the bytes payload of the callback.
548 ShellData actualShellData;
549 ASSERT_TRUE(actualShellData.ParseFromArray(payload.data(), payload.size()));
550
551 ShellData expectedShellData;
552 expectedShellData.add_atom()->mutable_screen_state_changed()->set_state(
553 ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
554 expectedShellData.add_elapsed_timestamp_nanos(1000);
555
556 EXPECT_THAT(actualShellData, EqShellData(expectedShellData));
557
558 auto subscriptionStats = getStatsdStatsReport().subscription_stats();
559 ASSERT_THAT(subscriptionStats.per_subscription_stats_size(), Eq(1));
560 EXPECT_THAT(subscriptionStats.per_subscription_stats(0).end_time_sec(), Gt(0));
561
562 // This event is ignored as the subscription has ended.
563 shellSubscriber.onLogEvent(*CreateScreenStateChangedEvent(
564 1000 /*timestamp*/, ::android::view::DisplayStateEnum::DISPLAY_STATE_ON));
565
566 // This should be a no-op as we've already unsubscribed.
567 shellSubscriber.unsubscribe(callback);
568
569 auto subscriptionStats2 = getStatsdStatsReport().subscription_stats();
570 ASSERT_THAT(subscriptionStats2.per_subscription_stats_size(), Eq(1));
571 EXPECT_THAT(subscriptionStats2.per_subscription_stats(0).end_time_sec(),
572 Eq(subscriptionStats.per_subscription_stats(0).end_time_sec()));
573 }
574
TEST_F(ShellSubscriberCallbackTest,testUnsubscribeEmptyCache)575 TEST_F(ShellSubscriberCallbackTest, testUnsubscribeEmptyCache) {
576 // Expect callback to be invoked once.
577 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(Exactly(1)).RetiresOnSaturation();
578 Expectation newSubcriptionEvent =
579 EXPECT_CALL(*mockLogEventFilter,
580 setAtomIds(CreateAtomIdSetFromShellSubscriptionBytes(configBytes),
581 &shellSubscriber))
582 .Times(1);
583 LogEventFilter::AtomIdSet idSetEmpty;
584 EXPECT_CALL(*mockLogEventFilter, setAtomIds(idSetEmpty, &shellSubscriber))
585 .Times(1)
586 .After(newSubcriptionEvent)
587 .RetiresOnSaturation();
588
589 shellSubscriber.startNewSubscription(configBytes, callback);
590
591 shellSubscriber.unsubscribe(callback);
592
593 EXPECT_THAT(reason, Eq(StatsSubscriptionCallbackReason::SUBSCRIPTION_ENDED));
594
595 // Get ShellData proto from the bytes payload of the callback.
596 ShellData actualShellData;
597 ASSERT_TRUE(actualShellData.ParseFromArray(payload.data(), payload.size()));
598
599 ShellData expectedShellData;
600
601 EXPECT_THAT(actualShellData, EqShellData(expectedShellData));
602 }
603
TEST_F(ShellSubscriberCallbackTest,testTruncateTimestampAtom)604 TEST_F(ShellSubscriberCallbackTest, testTruncateTimestampAtom) {
605 // Expect callback to be invoked once.
606 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(Exactly(1)).RetiresOnSaturation();
607 EXPECT_CALL(
608 *mockLogEventFilter,
609 setAtomIds(CreateAtomIdSetFromShellSubscriptionBytes(configBytes), &shellSubscriber))
610 .Times(1);
611 shellSubscriber.startNewSubscription(configBytes, callback);
612
613 shellSubscriber.onLogEvent(*CreatePhoneSignalStrengthChangedEvent(
614 NS_PER_SEC * 5 * 60 + 1000 /*timestamp*/,
615 ::android::telephony::SignalStrengthEnum::SIGNAL_STRENGTH_GOOD));
616
617 shellSubscriber.flushSubscription(callback);
618
619 // Get ShellData proto from the bytes payload of the callback.
620 ShellData actualShellData;
621 ASSERT_TRUE(actualShellData.ParseFromArray(payload.data(), payload.size()));
622
623 ShellData expectedShellData;
624 expectedShellData.add_atom()->mutable_phone_signal_strength_changed()->set_signal_strength(
625 ::android::telephony::SignalStrengthEnum::SIGNAL_STRENGTH_GOOD);
626 expectedShellData.add_elapsed_timestamp_nanos(NS_PER_SEC * 5 * 60);
627
628 EXPECT_THAT(actualShellData, EqShellData(expectedShellData));
629 }
630
TEST_F(ShellSubscriberCallbackPulledTest,testPullIfNeededBeforeInterval)631 TEST_F(ShellSubscriberCallbackPulledTest, testPullIfNeededBeforeInterval) {
632 // Pull should not happen
633 EXPECT_CALL(*pullerManager, Pull(_, A<const vector<int32_t>&>(), _, _)).Times(Exactly(0));
634
635 // Expect callback to not be invoked.
636 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(Exactly(0));
637
638 shellSubscriberClient->pullAndSendHeartbeatsIfNeeded(/* nowSecs= */ 0, /* nowMillis= */ 0,
639 /* nowNanos= */ 0);
640 }
641
TEST_F(ShellSubscriberCallbackPulledTest,testPullAtInterval)642 TEST_F(ShellSubscriberCallbackPulledTest, testPullAtInterval) {
643 // Pull should happen once. The data is cached.
644 EXPECT_CALL(*pullerManager, Pull(_, A<const vector<int32_t>&>(), _, _)).Times(Exactly(1));
645
646 // Expect callback to not be invoked.
647 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(Exactly(0));
648
649 // This pull should NOT trigger a cache flush.
650 shellSubscriberClient->pullAndSendHeartbeatsIfNeeded(/* nowSecs= */ 61, /* nowMillis= */ 61'000,
651 /* nowNanos= */ 61'000'000'000);
652 }
653
TEST_F(ShellSubscriberCallbackPulledTest,testCachedPullIsFlushed)654 TEST_F(ShellSubscriberCallbackPulledTest, testCachedPullIsFlushed) {
655 // Pull should happen once. The data is cached.
656 EXPECT_CALL(*pullerManager, Pull(_, A<const vector<int32_t>&>(), _, _)).Times(Exactly(1));
657
658 // This pull should NOT trigger a cache flush.
659 shellSubscriberClient->pullAndSendHeartbeatsIfNeeded(/* nowSecs= */ 61, /* nowMillis= */ 61'000,
660 /* nowNanos= */ 61'000'000'000);
661
662 // Expect callback to be invoked once flush is requested.
663 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(Exactly(1));
664
665 // This should flush out data cached from the pull.
666 shellSubscriberClient->flush();
667
668 EXPECT_THAT(reason, Eq(StatsSubscriptionCallbackReason::FLUSH_REQUESTED));
669
670 // Get ShellData proto from the bytes payload of the callback.
671 ShellData actualShellData;
672 ASSERT_TRUE(actualShellData.ParseFromArray(payload.data(), payload.size()));
673
674 EXPECT_THAT(actualShellData, EqShellData(getExpectedPulledData()));
675 }
676
TEST_F(ShellSubscriberCallbackPulledTest,testPullAtCacheTimeout)677 TEST_F(ShellSubscriberCallbackPulledTest, testPullAtCacheTimeout) {
678 // Pull should happen once. The data is flushed.
679 EXPECT_CALL(*pullerManager, Pull(_, A<const vector<int32_t>&>(), _, _)).Times(Exactly(1));
680
681 // Expect callback to be invoked.
682 EXPECT_CALL(*callback, onSubscriptionData(_, _)).Times(Exactly(1));
683
684 // This pull should trigger a cache flush.
685 shellSubscriberClient->pullAndSendHeartbeatsIfNeeded(/* nowSecs= */ 70, /* nowMillis= */ 70'000,
686 /* nowNanos= */ 70'000'000'000);
687
688 EXPECT_THAT(reason, Eq(StatsSubscriptionCallbackReason::STATSD_INITIATED));
689
690 // Get ShellData proto from the bytes payload of the callback.
691 ShellData actualShellData;
692 ASSERT_TRUE(actualShellData.ParseFromArray(payload.data(), payload.size()));
693
694 EXPECT_THAT(actualShellData, EqShellData(getExpectedPulledData()));
695 }
696
TEST_F(ShellSubscriberCallbackPulledTest,testPullFrequencyTooShort)697 TEST_F(ShellSubscriberCallbackPulledTest, testPullFrequencyTooShort) {
698 // Pull should NOT happen.
699 EXPECT_CALL(*pullerManager, Pull(_, A<const vector<int32_t>&>(), _, _)).Times(Exactly(0));
700
701 // This should not trigger a pull even though the timestamp passed in matches the pull interval
702 // specified in the config.
703 const int64_t sleepTimeMs =
704 shellSubscriberClient->pullAndSendHeartbeatsIfNeeded(2, 2000, 2'000'000'000);
705 }
706
TEST_F(ShellSubscriberCallbackPulledTest,testMinSleep)707 TEST_F(ShellSubscriberCallbackPulledTest, testMinSleep) {
708 // Pull should NOT happen.
709 EXPECT_CALL(*pullerManager, Pull(_, A<const vector<int32_t>&>(), _, _)).Times(Exactly(0));
710
711 const int64_t sleepTimeMs =
712 shellSubscriberClient->pullAndSendHeartbeatsIfNeeded(59, 59'000, 59'000'000'000);
713
714 // Even though there is only 1000 ms left until the next pull, the sleep time returned is
715 // kMinCallbackSleepIntervalMs.
716 EXPECT_THAT(sleepTimeMs, Eq(ShellSubscriberClient::kMinCallbackSleepIntervalMs));
717 }
718
TEST(ShellSubscriberTest,testPushedSubscription)719 TEST(ShellSubscriberTest, testPushedSubscription) {
720 sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
721 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
722
723 vector<std::shared_ptr<LogEvent>> pushedList = getPushedEvents();
724
725 // create a simple config to get screen events
726 ShellSubscription config;
727 config.add_pushed()->set_atom_id(SCREEN_STATE_CHANGED);
728
729 // this is the expected screen event atom.
730 vector<ShellData> expectedData;
731 ShellData shellData1;
732 shellData1.add_atom()->mutable_screen_state_changed()->set_state(
733 ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
734 shellData1.add_elapsed_timestamp_nanos(pushedList[0]->GetElapsedTimestampNs());
735 ShellData shellData2;
736 shellData2.add_atom()->mutable_screen_state_changed()->set_state(
737 ::android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
738 shellData2.add_elapsed_timestamp_nanos(pushedList[1]->GetElapsedTimestampNs());
739 expectedData.push_back(shellData1);
740 expectedData.push_back(shellData2);
741
742 // Test with single client
743 TRACE_CALL(runShellTest, config, uidMap, pullerManager, pushedList, expectedData,
744 kSingleClient);
745
746 // Test with multiple client
747 TRACE_CALL(runShellTest, config, uidMap, pullerManager, pushedList, expectedData, kNumClients);
748 }
749
TEST(ShellSubscriberTest,testPulledSubscription)750 TEST(ShellSubscriberTest, testPulledSubscription) {
751 sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
752 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
753
754 const vector<int32_t> uids = {AID_SYSTEM};
755 EXPECT_CALL(*pullerManager, Pull(CPU_ACTIVE_TIME, uids, _, _))
756 .WillRepeatedly(Invoke([](int tagId, const vector<int32_t>&, const int64_t,
757 vector<std::shared_ptr<LogEvent>>* data) {
758 data->clear();
759 data->push_back(makeCpuActiveTimeAtom(/*uid=*/kUid1, /*timeMillis=*/kCpuTime1));
760 data->push_back(makeCpuActiveTimeAtom(/*uid=*/kUid2, /*timeMillis=*/kCpuTime2));
761 return true;
762 }));
763
764 // Test with single client
765 TRACE_CALL(runShellTest, getPulledConfig(), uidMap, pullerManager, /*pushedEvents=*/{},
766 {getExpectedPulledData()}, kSingleClient);
767
768 // Test with multiple clients.
769 TRACE_CALL(runShellTest, getPulledConfig(), uidMap, pullerManager, {},
770 {getExpectedPulledData()}, kNumClients);
771 }
772
TEST(ShellSubscriberTest,testBothSubscriptions)773 TEST(ShellSubscriberTest, testBothSubscriptions) {
774 sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
775 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
776
777 const vector<int32_t> uids = {AID_SYSTEM};
778 EXPECT_CALL(*pullerManager, Pull(CPU_ACTIVE_TIME, uids, _, _))
779 .WillRepeatedly(Invoke([](int tagId, const vector<int32_t>&, const int64_t,
780 vector<std::shared_ptr<LogEvent>>* data) {
781 data->clear();
782 data->push_back(makeCpuActiveTimeAtom(/*uid=*/kUid1, /*timeMillis=*/kCpuTime1));
783 data->push_back(makeCpuActiveTimeAtom(/*uid=*/kUid2, /*timeMillis=*/kCpuTime2));
784 return true;
785 }));
786
787 vector<std::shared_ptr<LogEvent>> pushedList = getPushedEvents();
788
789 ShellSubscription config = getPulledConfig();
790 config.add_pushed()->set_atom_id(SCREEN_STATE_CHANGED);
791
792 vector<ShellData> expectedData;
793 ShellData shellData1;
794 shellData1.add_atom()->mutable_screen_state_changed()->set_state(
795 ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
796 shellData1.add_elapsed_timestamp_nanos(pushedList[0]->GetElapsedTimestampNs());
797 ShellData shellData2;
798 shellData2.add_atom()->mutable_screen_state_changed()->set_state(
799 ::android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
800 shellData2.add_elapsed_timestamp_nanos(pushedList[1]->GetElapsedTimestampNs());
801 expectedData.push_back(getExpectedPulledData());
802 expectedData.push_back(shellData1);
803 expectedData.push_back(shellData2);
804
805 // Test with single client
806 TRACE_CALL(runShellTest, config, uidMap, pullerManager, pushedList, expectedData,
807 kSingleClient);
808
809 // Test with multiple client
810 TRACE_CALL(runShellTest, config, uidMap, pullerManager, pushedList, expectedData, kNumClients);
811 }
812
TEST(ShellSubscriberTest,testMaxSizeGuard)813 TEST(ShellSubscriberTest, testMaxSizeGuard) {
814 sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
815 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
816 sp<ShellSubscriber> shellManager =
817 new ShellSubscriber(uidMap, pullerManager, std::make_shared<LogEventFilter>());
818
819 // set up 2 pipes for read/write config and data
820 int fds_config[2];
821 ASSERT_EQ(0, pipe2(fds_config, O_CLOEXEC));
822
823 int fds_data[2];
824 ASSERT_EQ(0, pipe2(fds_data, O_CLOEXEC));
825
826 // write invalid size of the config
827 size_t invalidBufferSize = (shellManager->getMaxSizeKb() * 1024) + 1;
828 write(fds_config[1], &invalidBufferSize, sizeof(invalidBufferSize));
829 close(fds_config[1]);
830 close(fds_data[0]);
831
832 EXPECT_FALSE(shellManager->startNewSubscription(fds_config[0], fds_data[1], /*timeoutSec=*/-1));
833 close(fds_config[0]);
834 close(fds_data[1]);
835 }
836
TEST(ShellSubscriberTest,testMaxSubscriptionsGuard)837 TEST(ShellSubscriberTest, testMaxSubscriptionsGuard) {
838 sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
839 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
840 sp<ShellSubscriber> shellManager =
841 new ShellSubscriber(uidMap, pullerManager, std::make_shared<LogEventFilter>());
842
843 // create a simple config to get screen events
844 ShellSubscription config;
845 config.add_pushed()->set_atom_id(SCREEN_STATE_CHANGED);
846
847 size_t bufferSize = config.ByteSize();
848 vector<uint8_t> buffer(bufferSize);
849 config.SerializeToArray(&buffer[0], bufferSize);
850
851 size_t maxSubs = shellManager->getMaxSubscriptions();
852 int fds_configs[maxSubs + 1][2];
853 int fds_datas[maxSubs + 1][2];
854 for (int i = 0; i < maxSubs; i++) {
855 // set up 2 pipes for read/write config and data
856 ASSERT_EQ(0, pipe2(fds_configs[i], O_CLOEXEC));
857 ASSERT_EQ(0, pipe2(fds_datas[i], O_CLOEXEC));
858
859 // write the config to pipe, first write size of the config
860 write(fds_configs[i][1], &bufferSize, sizeof(bufferSize));
861 // then write config itself
862 write(fds_configs[i][1], buffer.data(), bufferSize);
863 close(fds_configs[i][1]);
864
865 EXPECT_TRUE(shellManager->startNewSubscription(fds_configs[i][0], fds_datas[i][1],
866 /*timeoutSec=*/-1));
867 close(fds_configs[i][0]);
868 close(fds_datas[i][1]);
869 }
870 ASSERT_EQ(0, pipe2(fds_configs[maxSubs], O_CLOEXEC));
871 ASSERT_EQ(0, pipe2(fds_datas[maxSubs], O_CLOEXEC));
872
873 // write the config to pipe, first write size of the config
874 write(fds_configs[maxSubs][1], &bufferSize, sizeof(bufferSize));
875 // then write config itself
876 write(fds_configs[maxSubs][1], buffer.data(), bufferSize);
877 close(fds_configs[maxSubs][1]);
878
879 EXPECT_FALSE(shellManager->startNewSubscription(fds_configs[maxSubs][0], fds_datas[maxSubs][1],
880 /*timeoutSec=*/-1));
881 close(fds_configs[maxSubs][0]);
882 close(fds_datas[maxSubs][1]);
883
884 // Not closing fds_datas[i][0] because this causes writes within ShellSubscriberClient to hang
885 }
886
TEST(ShellSubscriberTest,testDifferentConfigs)887 TEST(ShellSubscriberTest, testDifferentConfigs) {
888 sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
889 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
890 sp<ShellSubscriber> shellManager =
891 new ShellSubscriber(uidMap, pullerManager, std::make_shared<LogEventFilter>());
892
893 // number of different configs
894 int numConfigs = 2;
895
896 // create a simple config to get screen events
897 ShellSubscription configs[numConfigs];
898 configs[0].add_pushed()->set_atom_id(SCREEN_STATE_CHANGED);
899 configs[1].add_pushed()->set_atom_id(PLUGGED_STATE_CHANGED);
900
901 vector<vector<uint8_t>> configBuffers;
902 for (int i = 0; i < numConfigs; i++) {
903 size_t bufferSize = configs[i].ByteSize();
904 vector<uint8_t> buffer(bufferSize);
905 configs[i].SerializeToArray(&buffer[0], bufferSize);
906 configBuffers.push_back(buffer);
907 }
908
909 int fds_configs[numConfigs][2];
910 int fds_datas[numConfigs][2];
911 for (int i = 0; i < numConfigs; i++) {
912 // set up 2 pipes for read/write config and data
913 ASSERT_EQ(0, pipe2(fds_configs[i], O_CLOEXEC));
914 ASSERT_EQ(0, pipe2(fds_datas[i], O_CLOEXEC));
915
916 size_t configSize = configBuffers[i].size();
917 // write the config to pipe, first write size of the config
918 write(fds_configs[i][1], &configSize, sizeof(configSize));
919 // then write config itself
920 write(fds_configs[i][1], configBuffers[i].data(), configSize);
921 close(fds_configs[i][1]);
922
923 EXPECT_TRUE(shellManager->startNewSubscription(fds_configs[i][0], fds_datas[i][1],
924 /*timeoutSec=*/-1));
925 close(fds_configs[i][0]);
926 close(fds_datas[i][1]);
927 }
928
929 // send a log event that matches the config.
930 vector<std::shared_ptr<LogEvent>> pushedList = getPushedEvents();
931 for (const auto& event : pushedList) {
932 shellManager->onLogEvent(*event);
933 }
934
935 // Validate Config 1
936 ShellData actual1 = readData(fds_datas[0][0]);
937 ShellData expected1;
938 expected1.add_atom()->mutable_screen_state_changed()->set_state(
939 ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
940 expected1.add_elapsed_timestamp_nanos(pushedList[0]->GetElapsedTimestampNs());
941 EXPECT_THAT(expected1, EqShellData(actual1));
942
943 ShellData actual2 = readData(fds_datas[0][0]);
944 ShellData expected2;
945 expected2.add_atom()->mutable_screen_state_changed()->set_state(
946 ::android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
947 expected2.add_elapsed_timestamp_nanos(pushedList[1]->GetElapsedTimestampNs());
948 EXPECT_THAT(expected2, EqShellData(actual2));
949
950 // Validate Config 2, repeating the process
951 ShellData actual3 = readData(fds_datas[1][0]);
952 ShellData expected3;
953 expected3.add_atom()->mutable_plugged_state_changed()->set_state(
954 BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
955 expected3.add_elapsed_timestamp_nanos(pushedList[2]->GetElapsedTimestampNs());
956 EXPECT_THAT(expected3, EqShellData(actual3));
957
958 ShellData actual4 = readData(fds_datas[1][0]);
959 ShellData expected4;
960 expected4.add_atom()->mutable_plugged_state_changed()->set_state(
961 BatteryPluggedStateEnum::BATTERY_PLUGGED_NONE);
962 expected4.add_elapsed_timestamp_nanos(pushedList[3]->GetElapsedTimestampNs());
963 EXPECT_THAT(expected4, EqShellData(actual4));
964
965 // Not closing fds_datas[i][0] because this causes writes within ShellSubscriberClient to hang
966 }
967
TEST(ShellSubscriberTest,testPushedSubscriptionRestrictedEvent)968 TEST(ShellSubscriberTest, testPushedSubscriptionRestrictedEvent) {
969 sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
970 sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
971
972 std::vector<shared_ptr<LogEvent>> pushedList;
973 pushedList.push_back(CreateRestrictedLogEvent(/*atomTag=*/10, /*timestamp=*/1000));
974
975 // create a simple config to get screen events
976 ShellSubscription config;
977 config.add_pushed()->set_atom_id(10);
978
979 // expect empty data
980 vector<ShellData> expectedData;
981
982 // Test with single client
983 TRACE_CALL(runShellTest, config, uidMap, pullerManager, pushedList, expectedData,
984 kSingleClient);
985
986 // Test with multiple client
987 TRACE_CALL(runShellTest, config, uidMap, pullerManager, pushedList, expectedData, kNumClients);
988 }
989
990 #else
991 GTEST_LOG_(INFO) << "This test does nothing.\n";
992 #endif
993
994 } // namespace statsd
995 } // namespace os
996 } // namespace android
997