1// Copyright (C) 2017 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 <gtest/gtest.h> 16 17#include "src/StatsLogProcessor.h" 18#include "src/stats_log_util.h" 19#include "tests/statsd_test_util.h" 20 21#include <vector> 22 23namespace android { 24namespace os { 25namespace statsd { 26 27#ifdef __ANDROID__ 28namespace { 29 30StatsdConfig CreateStatsdConfig() { 31 StatsdConfig config; 32 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root. 33 34 *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher(); 35 *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher(); 36 37 *config.add_atom_matcher() = CreateSyncStartAtomMatcher(); 38 *config.add_atom_matcher() = CreateSyncEndAtomMatcher(); 39 40 *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher(); 41 *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher(); 42 43 auto appCrashMatcher = CreateProcessCrashAtomMatcher(); 44 *config.add_atom_matcher() = appCrashMatcher; 45 46 auto screenIsOffPredicate = CreateScreenIsOffPredicate(); 47 48 auto isSyncingPredicate = CreateIsSyncingPredicate(); 49 auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions(); 50 *syncDimension = CreateAttributionUidDimensions( 51 android::util::SYNC_STATE_CHANGED, {Position::FIRST}); 52 syncDimension->add_child()->set_field(2 /* name field*/); 53 54 auto isInBackgroundPredicate = CreateIsInBackgroundPredicate(); 55 *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() = 56 CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ }); 57 58 *config.add_predicate() = screenIsOffPredicate; 59 *config.add_predicate() = isSyncingPredicate; 60 *config.add_predicate() = isInBackgroundPredicate; 61 62 auto combinationPredicate = config.add_predicate(); 63 combinationPredicate->set_id(StringToId("combinationPredicate")); 64 combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND); 65 addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate); 66 addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate); 67 addPredicateToPredicateCombination(isInBackgroundPredicate, combinationPredicate); 68 69 auto countMetric = config.add_count_metric(); 70 countMetric->set_id(StringToId("AppCrashes")); 71 countMetric->set_what(appCrashMatcher.id()); 72 countMetric->set_condition(combinationPredicate->id()); 73 // The metric is dimensioning by uid only. 74 *countMetric->mutable_dimensions_in_what() = 75 CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1}); 76 countMetric->set_bucket(FIVE_MINUTES); 77 78 // Links between crash atom and condition of app is in syncing. 79 auto links = countMetric->add_links(); 80 links->set_condition(isSyncingPredicate.id()); 81 auto dimensionWhat = links->mutable_fields_in_what(); 82 dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED); 83 dimensionWhat->add_child()->set_field(1); // uid field. 84 *links->mutable_fields_in_condition() = CreateAttributionUidDimensions( 85 android::util::SYNC_STATE_CHANGED, {Position::FIRST}); 86 87 // Links between crash atom and condition of app is in background. 88 links = countMetric->add_links(); 89 links->set_condition(isInBackgroundPredicate.id()); 90 dimensionWhat = links->mutable_fields_in_what(); 91 dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED); 92 dimensionWhat->add_child()->set_field(1); // uid field. 93 auto dimensionCondition = links->mutable_fields_in_condition(); 94 dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED); 95 dimensionCondition->add_child()->set_field(1); // uid field. 96 return config; 97} 98} // namespace 99 100// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests, 101// we should use the real API which will clear the data after dump data is called. 102// TODO: better refactor the code so that the tests are not so verbose. 103TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) { 104 auto config = CreateStatsdConfig(); 105 uint64_t bucketStartTimeNs = 10000000000; 106 uint64_t bucketSizeNs = 107 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; 108 109 ConfigKey cfgKey; 110 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); 111 EXPECT_EQ(processor->mMetricsManagers.size(), 1u); 112 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); 113 114 int appUid = 123; 115 auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1); 116 auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201); 117 auto crashEvent3= CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101); 118 119 auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51); 120 auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299); 121 auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001); 122 123 auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16); 124 auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249); 125 126 auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351); 127 auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2); 128 129 auto screenTurnedOnEvent = 130 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, 131 bucketStartTimeNs + 2); 132 auto screenTurnedOffEvent = 133 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, 134 bucketStartTimeNs + 200); 135 auto screenTurnedOnEvent2 = 136 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, 137 bucketStartTimeNs + 2 * bucketSizeNs - 100); 138 139 std::vector<AttributionNodeInternal> attributions = { 140 CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")}; 141 auto syncOnEvent1 = 142 CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50); 143 auto syncOffEvent1 = 144 CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300); 145 auto syncOnEvent2 = 146 CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000); 147 148 auto moveToBackgroundEvent1 = 149 CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15); 150 auto moveToForegroundEvent1 = 151 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250); 152 153 auto moveToBackgroundEvent2 = 154 CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350); 155 auto moveToForegroundEvent2 = 156 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1); 157 158 /* 159 bucket #1 bucket #2 160 161 162 | | | | | | | | | | (crashEvents) 163 |-------------------------------------|-----------------------------------|--------- 164 165 | | (MoveToBkground) 166 167 | | (MoveToForeground) 168 169 | | (SyncIsOn) 170 | (SyncIsOff) 171 | | (ScreenIsOn) 172 | (ScreenIsOff) 173 */ 174 std::vector<std::unique_ptr<LogEvent>> events; 175 events.push_back(std::move(crashEvent1)); 176 events.push_back(std::move(crashEvent2)); 177 events.push_back(std::move(crashEvent3)); 178 events.push_back(std::move(crashEvent4)); 179 events.push_back(std::move(crashEvent5)); 180 events.push_back(std::move(crashEvent6)); 181 events.push_back(std::move(crashEvent7)); 182 events.push_back(std::move(crashEvent8)); 183 events.push_back(std::move(crashEvent9)); 184 events.push_back(std::move(crashEvent10)); 185 events.push_back(std::move(screenTurnedOnEvent)); 186 events.push_back(std::move(screenTurnedOffEvent)); 187 events.push_back(std::move(screenTurnedOnEvent2)); 188 events.push_back(std::move(syncOnEvent1)); 189 events.push_back(std::move(syncOffEvent1)); 190 events.push_back(std::move(syncOnEvent2)); 191 events.push_back(std::move(moveToBackgroundEvent1)); 192 events.push_back(std::move(moveToForegroundEvent1)); 193 events.push_back(std::move(moveToBackgroundEvent2)); 194 events.push_back(std::move(moveToForegroundEvent2)); 195 196 sortLogEventsByTimestamp(&events); 197 198 for (const auto& event : events) { 199 processor->OnLogEvent(event.get()); 200 } 201 ConfigMetricsReportList reports; 202 vector<uint8_t> buffer; 203 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP, 204 &buffer); 205 EXPECT_TRUE(buffer.size() > 0); 206 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); 207 backfillDimensionPath(&reports); 208 backfillStringInReport(&reports); 209 backfillStartEndTimestamp(&reports); 210 EXPECT_EQ(reports.reports_size(), 1); 211 EXPECT_EQ(reports.reports(0).metrics_size(), 1); 212 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1); 213 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1); 214 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1); 215 auto data = reports.reports(0).metrics(0).count_metrics().data(0); 216 // Validate dimension value. 217 EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED); 218 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1); 219 // Uid field. 220 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1); 221 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid); 222} 223 224TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) { 225 auto config = CreateStatsdConfig(); 226 uint64_t bucketStartTimeNs = 10000000000; 227 uint64_t bucketSizeNs = 228 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; 229 230 ConfigKey cfgKey; 231 auto processor = CreateStatsLogProcessor( 232 bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); 233 EXPECT_EQ(processor->mMetricsManagers.size(), 1u); 234 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); 235 236 int appUid = 123; 237 auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1); 238 auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201); 239 auto crashEvent3 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101); 240 241 auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51); 242 auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299); 243 auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001); 244 245 auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16); 246 auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249); 247 248 auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351); 249 auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2); 250 251 auto screenTurnedOnEvent = CreateScreenStateChangedEvent( 252 android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 2); 253 auto screenTurnedOffEvent = CreateScreenStateChangedEvent( 254 android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200); 255 auto screenTurnedOnEvent2 = 256 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, 257 bucketStartTimeNs + 2 * bucketSizeNs - 100); 258 259 std::vector<AttributionNodeInternal> attributions = { 260 CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")}; 261 auto syncOnEvent1 = CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50); 262 auto syncOffEvent1 = 263 CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300); 264 auto syncOnEvent2 = 265 CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000); 266 267 auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15); 268 auto moveToForegroundEvent1 = 269 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250); 270 271 auto moveToBackgroundEvent2 = 272 CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350); 273 auto moveToForegroundEvent2 = 274 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1); 275 276 /* 277 bucket #1 bucket #2 278 279 280 | | | | | | | | | | (crashEvents) 281 |-------------------------------------|-----------------------------------|--------- 282 283 | | (MoveToBkground) 284 285 | | (MoveToForeground) 286 287 | | (SyncIsOn) 288 | (SyncIsOff) 289 | | (ScreenIsOn) 290 | (ScreenIsOff) 291 */ 292 std::vector<std::unique_ptr<LogEvent>> events; 293 events.push_back(std::move(crashEvent1)); 294 events.push_back(std::move(crashEvent2)); 295 events.push_back(std::move(crashEvent3)); 296 events.push_back(std::move(crashEvent4)); 297 events.push_back(std::move(crashEvent5)); 298 events.push_back(std::move(crashEvent6)); 299 events.push_back(std::move(crashEvent7)); 300 events.push_back(std::move(crashEvent8)); 301 events.push_back(std::move(crashEvent9)); 302 events.push_back(std::move(crashEvent10)); 303 events.push_back(std::move(screenTurnedOnEvent)); 304 events.push_back(std::move(screenTurnedOffEvent)); 305 events.push_back(std::move(screenTurnedOnEvent2)); 306 events.push_back(std::move(syncOnEvent1)); 307 events.push_back(std::move(syncOffEvent1)); 308 events.push_back(std::move(syncOnEvent2)); 309 events.push_back(std::move(moveToBackgroundEvent1)); 310 events.push_back(std::move(moveToForegroundEvent1)); 311 events.push_back(std::move(moveToBackgroundEvent2)); 312 events.push_back(std::move(moveToForegroundEvent2)); 313 314 sortLogEventsByTimestamp(&events); 315 316 for (const auto& event : events) { 317 processor->OnLogEvent(event.get()); 318 } 319 ConfigMetricsReportList reports; 320 vector<uint8_t> buffer; 321 322 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP, 323 &buffer); 324 EXPECT_TRUE(buffer.size() > 0); 325 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); 326 backfillDimensionPath(&reports); 327 backfillStringInReport(&reports); 328 backfillStartEndTimestamp(&reports); 329 EXPECT_EQ(reports.reports_size(), 1); 330 EXPECT_EQ(reports.reports(0).metrics_size(), 1); 331 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1); 332 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2); 333 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1); 334 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3); 335 auto data = reports.reports(0).metrics(0).count_metrics().data(0); 336 // Validate dimension value. 337 EXPECT_EQ(data.dimensions_in_what().field(), 338 android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED); 339 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1); 340 // Uid field. 341 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1); 342 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid); 343} 344 345#else 346GTEST_LOG_(INFO) << "This test does nothing.\n"; 347#endif 348 349} // namespace statsd 350} // namespace os 351} // namespace android 352