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 23 namespace android { 24 namespace os { 25 namespace statsd { 26 27 #ifdef __ANDROID__ 28 namespace { 29 30 StatsdConfig 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 TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) { 103 auto config = CreateStatsdConfig(); 104 uint64_t bucketStartTimeNs = 10000000000; 105 uint64_t bucketSizeNs = 106 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; 107 108 ConfigKey cfgKey; 109 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); 110 EXPECT_EQ(processor->mMetricsManagers.size(), 1u); 111 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); 112 113 int appUid = 123; 114 auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1); 115 auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201); 116 auto crashEvent3= CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101); 117 118 auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51); 119 auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299); 120 auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001); 121 122 auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16); 123 auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249); 124 125 auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351); 126 auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2); 127 128 auto screenTurnedOnEvent = 129 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, 130 bucketStartTimeNs + 2); 131 auto screenTurnedOffEvent = 132 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, 133 bucketStartTimeNs + 200); 134 auto screenTurnedOnEvent2 = 135 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, 136 bucketStartTimeNs + 2 * bucketSizeNs - 100); 137 138 std::vector<AttributionNodeInternal> attributions = { 139 CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")}; 140 auto syncOnEvent1 = 141 CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50); 142 auto syncOffEvent1 = 143 CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300); 144 auto syncOnEvent2 = 145 CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000); 146 147 auto moveToBackgroundEvent1 = 148 CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15); 149 auto moveToForegroundEvent1 = 150 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250); 151 152 auto moveToBackgroundEvent2 = 153 CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350); 154 auto moveToForegroundEvent2 = 155 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1); 156 157 /* 158 bucket #1 bucket #2 159 160 161 | | | | | | | | | | (crashEvents) 162 |-------------------------------------|-----------------------------------|--------- 163 164 | | (MoveToBkground) 165 166 | | (MoveToForeground) 167 168 | | (SyncIsOn) 169 | (SyncIsOff) 170 | | (ScreenIsOn) 171 | (ScreenIsOff) 172 */ 173 std::vector<std::unique_ptr<LogEvent>> events; 174 events.push_back(std::move(crashEvent1)); 175 events.push_back(std::move(crashEvent2)); 176 events.push_back(std::move(crashEvent3)); 177 events.push_back(std::move(crashEvent4)); 178 events.push_back(std::move(crashEvent5)); 179 events.push_back(std::move(crashEvent6)); 180 events.push_back(std::move(crashEvent7)); 181 events.push_back(std::move(crashEvent8)); 182 events.push_back(std::move(crashEvent9)); 183 events.push_back(std::move(crashEvent10)); 184 events.push_back(std::move(screenTurnedOnEvent)); 185 events.push_back(std::move(screenTurnedOffEvent)); 186 events.push_back(std::move(screenTurnedOnEvent2)); 187 events.push_back(std::move(syncOnEvent1)); 188 events.push_back(std::move(syncOffEvent1)); 189 events.push_back(std::move(syncOnEvent2)); 190 events.push_back(std::move(moveToBackgroundEvent1)); 191 events.push_back(std::move(moveToForegroundEvent1)); 192 events.push_back(std::move(moveToBackgroundEvent2)); 193 events.push_back(std::move(moveToForegroundEvent2)); 194 195 sortLogEventsByTimestamp(&events); 196 197 for (const auto& event : events) { 198 processor->OnLogEvent(event.get()); 199 } 200 ConfigMetricsReportList reports; 201 vector<uint8_t> buffer; 202 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, 203 ADB_DUMP, FAST, &buffer); 204 EXPECT_TRUE(buffer.size() > 0); 205 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); 206 backfillDimensionPath(&reports); 207 backfillStringInReport(&reports); 208 backfillStartEndTimestamp(&reports); 209 EXPECT_EQ(reports.reports_size(), 1); 210 EXPECT_EQ(reports.reports(0).metrics_size(), 1); 211 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1); 212 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1); 213 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1); 214 auto data = reports.reports(0).metrics(0).count_metrics().data(0); 215 // Validate dimension value. 216 EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED); 217 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1); 218 // Uid field. 219 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1); 220 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid); 221 } 222 223 TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) { 224 auto config = CreateStatsdConfig(); 225 uint64_t bucketStartTimeNs = 10000000000; 226 uint64_t bucketSizeNs = 227 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL; 228 229 ConfigKey cfgKey; 230 auto processor = CreateStatsLogProcessor( 231 bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); 232 EXPECT_EQ(processor->mMetricsManagers.size(), 1u); 233 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); 234 235 int appUid = 123; 236 auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1); 237 auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201); 238 auto crashEvent3 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101); 239 240 auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51); 241 auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299); 242 auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001); 243 244 auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16); 245 auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249); 246 247 auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351); 248 auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2); 249 250 auto screenTurnedOnEvent = CreateScreenStateChangedEvent( 251 android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 2); 252 auto screenTurnedOffEvent = CreateScreenStateChangedEvent( 253 android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200); 254 auto screenTurnedOnEvent2 = 255 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON, 256 bucketStartTimeNs + 2 * bucketSizeNs - 100); 257 258 std::vector<AttributionNodeInternal> attributions = { 259 CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")}; 260 auto syncOnEvent1 = CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50); 261 auto syncOffEvent1 = 262 CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300); 263 auto syncOnEvent2 = 264 CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000); 265 266 auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15); 267 auto moveToForegroundEvent1 = 268 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250); 269 270 auto moveToBackgroundEvent2 = 271 CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350); 272 auto moveToForegroundEvent2 = 273 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1); 274 275 /* 276 bucket #1 bucket #2 277 278 279 | | | | | | | | | | (crashEvents) 280 |-------------------------------------|-----------------------------------|--------- 281 282 | | (MoveToBkground) 283 284 | | (MoveToForeground) 285 286 | | (SyncIsOn) 287 | (SyncIsOff) 288 | | (ScreenIsOn) 289 | (ScreenIsOff) 290 */ 291 std::vector<std::unique_ptr<LogEvent>> events; 292 events.push_back(std::move(crashEvent1)); 293 events.push_back(std::move(crashEvent2)); 294 events.push_back(std::move(crashEvent3)); 295 events.push_back(std::move(crashEvent4)); 296 events.push_back(std::move(crashEvent5)); 297 events.push_back(std::move(crashEvent6)); 298 events.push_back(std::move(crashEvent7)); 299 events.push_back(std::move(crashEvent8)); 300 events.push_back(std::move(crashEvent9)); 301 events.push_back(std::move(crashEvent10)); 302 events.push_back(std::move(screenTurnedOnEvent)); 303 events.push_back(std::move(screenTurnedOffEvent)); 304 events.push_back(std::move(screenTurnedOnEvent2)); 305 events.push_back(std::move(syncOnEvent1)); 306 events.push_back(std::move(syncOffEvent1)); 307 events.push_back(std::move(syncOnEvent2)); 308 events.push_back(std::move(moveToBackgroundEvent1)); 309 events.push_back(std::move(moveToForegroundEvent1)); 310 events.push_back(std::move(moveToBackgroundEvent2)); 311 events.push_back(std::move(moveToForegroundEvent2)); 312 313 sortLogEventsByTimestamp(&events); 314 315 for (const auto& event : events) { 316 processor->OnLogEvent(event.get()); 317 } 318 ConfigMetricsReportList reports; 319 vector<uint8_t> buffer; 320 321 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, 322 ADB_DUMP, FAST, &buffer); 323 EXPECT_TRUE(buffer.size() > 0); 324 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); 325 backfillDimensionPath(&reports); 326 backfillStringInReport(&reports); 327 backfillStartEndTimestamp(&reports); 328 EXPECT_EQ(reports.reports_size(), 1); 329 EXPECT_EQ(reports.reports(0).metrics_size(), 1); 330 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1); 331 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2); 332 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1); 333 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3); 334 auto data = reports.reports(0).metrics(0).count_metrics().data(0); 335 // Validate dimension value. 336 EXPECT_EQ(data.dimensions_in_what().field(), 337 android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED); 338 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1); 339 // Uid field. 340 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1); 341 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid); 342 } 343 344 #else 345 GTEST_LOG_(INFO) << "This test does nothing.\n"; 346 #endif 347 348 } // namespace statsd 349 } // namespace os 350 } // namespace android 351