• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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