1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "android.power.stats.vts" 18 19 #include <VtsHalHidlTargetTestBase.h> 20 #include <VtsHalHidlTargetTestEnvBase.h> 21 #include <android-base/logging.h> 22 #include <android/hardware/power/stats/1.0/IPowerStats.h> 23 #include <fmq/MessageQueue.h> 24 #include <hidl/MQDescriptor.h> 25 #include <inttypes.h> 26 #include <algorithm> 27 #include <random> 28 #include <thread> 29 30 namespace android { 31 namespace power { 32 namespace stats { 33 namespace vts { 34 namespace { 35 36 using android::sp; 37 using android::hardware::hidl_vec; 38 using android::hardware::kSynchronizedReadWrite; 39 using android::hardware::Return; 40 using android::hardware::Void; 41 using android::hardware::power::stats::V1_0::EnergyData; 42 using android::hardware::power::stats::V1_0::IPowerStats; 43 using android::hardware::power::stats::V1_0::PowerEntityInfo; 44 using android::hardware::power::stats::V1_0::PowerEntityStateResidencyResult; 45 using android::hardware::power::stats::V1_0::PowerEntityStateSpace; 46 using android::hardware::power::stats::V1_0::RailInfo; 47 using android::hardware::power::stats::V1_0::Status; 48 49 } // namespace 50 51 typedef hardware::MessageQueue<EnergyData, kSynchronizedReadWrite> MessageQueueSync; 52 // Test environment for Power HIDL HAL. 53 class PowerStatsHidlEnv : public ::testing::VtsHalHidlTargetTestEnvBase { 54 public: 55 // get the test environment singleton 56 static PowerStatsHidlEnv* Instance() { 57 static PowerStatsHidlEnv* instance = new PowerStatsHidlEnv; 58 return instance; 59 } 60 61 virtual void registerTestServices() override { registerTestService<IPowerStats>(); } 62 }; 63 64 class PowerStatsHidlTest : public ::testing::VtsHalHidlTargetTestBase { 65 public: 66 virtual void SetUp() override { 67 service_ = ::testing::VtsHalHidlTargetTestBase::getService<IPowerStats>( 68 PowerStatsHidlEnv::Instance()->getServiceName<IPowerStats>()); 69 ASSERT_NE(service_, nullptr); 70 } 71 72 virtual void TearDown() override {} 73 74 void getInfos(hidl_vec<PowerEntityInfo>& infos); 75 void getStateSpaces(hidl_vec<PowerEntityStateSpace>& stateSpaces, 76 const std::vector<uint32_t>& ids); 77 void getResidencyResults(hidl_vec<PowerEntityStateResidencyResult>& results, 78 const std::vector<uint32_t>& ids); 79 void getRandomIds(std::vector<uint32_t>& ids); 80 81 sp<IPowerStats> service_; 82 }; 83 84 void PowerStatsHidlTest::getInfos(hidl_vec<PowerEntityInfo>& infos) { 85 Status status; 86 Return<void> ret = service_->getPowerEntityInfo([&status, &infos](auto rInfos, auto rStatus) { 87 status = rStatus; 88 infos = rInfos; 89 }); 90 ASSERT_TRUE(ret.isOk()); 91 92 if (status == Status::SUCCESS) { 93 ASSERT_NE(infos.size(), 0) << "powerEntityInfos must have entries if supported"; 94 } else { 95 ASSERT_EQ(status, Status::NOT_SUPPORTED); 96 ASSERT_EQ(infos.size(), 0); 97 LOG(INFO) << "getPowerEntityInfo not supported"; 98 } 99 } 100 101 void PowerStatsHidlTest::getStateSpaces(hidl_vec<PowerEntityStateSpace>& stateSpaces, 102 const std::vector<uint32_t>& ids = {}) { 103 Status status; 104 Return<void> ret = service_->getPowerEntityStateInfo( 105 ids, [&status, &stateSpaces](auto rStateSpaces, auto rStatus) { 106 status = rStatus; 107 stateSpaces = rStateSpaces; 108 }); 109 ASSERT_TRUE(ret.isOk()); 110 111 if (status == Status::SUCCESS) { 112 ASSERT_NE(stateSpaces.size(), 0) << "powerEntityStateSpaces must have entries if supported"; 113 } else { 114 ASSERT_EQ(status, Status::NOT_SUPPORTED); 115 ASSERT_EQ(stateSpaces.size(), 0); 116 LOG(INFO) << "getPowerEntityStateInfo not supported"; 117 } 118 } 119 120 void PowerStatsHidlTest::getResidencyResults(hidl_vec<PowerEntityStateResidencyResult>& results, 121 const std::vector<uint32_t>& ids = {}) { 122 Status status; 123 Return<void> ret = service_->getPowerEntityStateResidencyData( 124 ids, [&status, &results](auto rResults, auto rStatus) { 125 status = rStatus; 126 results = rResults; 127 }); 128 ASSERT_TRUE(ret.isOk()); 129 130 if (status == Status::SUCCESS) { 131 ASSERT_NE(results.size(), 0); 132 } else { 133 ASSERT_EQ(status, Status::NOT_SUPPORTED); 134 ASSERT_EQ(results.size(), 0); 135 LOG(INFO) << "getPowerEntityStateResidencyData not supported"; 136 } 137 } 138 139 void PowerStatsHidlTest::getRandomIds(std::vector<uint32_t>& ids) { 140 hidl_vec<PowerEntityStateSpace> stateSpaces; 141 getStateSpaces(stateSpaces); 142 143 if (stateSpaces.size() == 0) { 144 return; 145 } 146 147 for (auto stateSpace : stateSpaces) { 148 ids.push_back(stateSpace.powerEntityId); 149 } 150 151 unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); 152 auto gen = std::default_random_engine(seed); 153 std::uniform_int_distribution<uint32_t> dist(1, stateSpaces.size()); 154 155 std::shuffle(ids.begin(), ids.end(), gen); 156 ids.resize(dist(gen)); 157 } 158 159 // Each PowerEntity must have a valid name 160 TEST_F(PowerStatsHidlTest, ValidatePowerEntityNames) { 161 hidl_vec<PowerEntityInfo> infos; 162 getInfos(infos); 163 for (auto info : infos) { 164 ASSERT_NE(info.powerEntityName, ""); 165 } 166 } 167 168 // Each PowerEntity must have a unique ID 169 TEST_F(PowerStatsHidlTest, ValidatePowerEntityIds) { 170 hidl_vec<PowerEntityInfo> infos; 171 getInfos(infos); 172 173 set<uint32_t> ids; 174 for (auto info : infos) { 175 ASSERT_TRUE(ids.insert(info.powerEntityId).second); 176 } 177 } 178 179 // Each PowerEntityStateSpace must have an associated PowerEntityInfo 180 TEST_F(PowerStatsHidlTest, ValidateStateInfoAssociation) { 181 hidl_vec<PowerEntityInfo> infos; 182 getInfos(infos); 183 184 hidl_vec<PowerEntityStateSpace> stateSpaces; 185 getStateSpaces(stateSpaces); 186 187 std::set<uint32_t> ids; 188 for (auto info : infos) { 189 ids.insert(info.powerEntityId); 190 } 191 192 for (auto stateSpace : stateSpaces) { 193 ASSERT_NE(ids.count(stateSpace.powerEntityId), 0); 194 } 195 } 196 197 // Each state must have a valid name 198 TEST_F(PowerStatsHidlTest, ValidateStateNames) { 199 hidl_vec<PowerEntityStateSpace> stateSpaces; 200 getStateSpaces(stateSpaces); 201 202 for (auto stateSpace : stateSpaces) { 203 for (auto state : stateSpace.states) { 204 ASSERT_NE(state.powerEntityStateName, ""); 205 } 206 } 207 } 208 209 // Each state must have an ID that is unique to the PowerEntityStateSpace 210 TEST_F(PowerStatsHidlTest, ValidateStateUniqueIds) { 211 hidl_vec<PowerEntityStateSpace> stateSpaces; 212 getStateSpaces(stateSpaces); 213 214 for (auto stateSpace : stateSpaces) { 215 set<uint32_t> stateIds; 216 for (auto state : stateSpace.states) { 217 ASSERT_TRUE(stateIds.insert(state.powerEntityStateId).second); 218 } 219 } 220 } 221 222 // getPowerEntityStateInfo must support passing in requested IDs 223 // Results must contain state space information for all requested IDs 224 TEST_F(PowerStatsHidlTest, ValidateStateInfoAssociationSelect) { 225 std::vector<uint32_t> randomIds; 226 getRandomIds(randomIds); 227 228 if (randomIds.empty()) { 229 return; 230 } 231 232 hidl_vec<PowerEntityStateSpace> stateSpaces; 233 getStateSpaces(stateSpaces, randomIds); 234 235 ASSERT_EQ(stateSpaces.size(), randomIds.size()); 236 237 std::set<uint32_t> ids; 238 for (auto id : randomIds) { 239 ids.insert(id); 240 } 241 for (auto stateSpace : stateSpaces) { 242 ASSERT_NE(ids.count(stateSpace.powerEntityId), 0); 243 } 244 } 245 246 // Requested state space info must match initially obtained stateinfos 247 TEST_F(PowerStatsHidlTest, ValidateStateInfoSelect) { 248 hidl_vec<PowerEntityStateSpace> stateSpaces; 249 getStateSpaces(stateSpaces); 250 if (stateSpaces.size() == 0) { 251 return; 252 } 253 254 std::vector<uint32_t> randomIds; 255 getRandomIds(randomIds); 256 ASSERT_FALSE(randomIds.empty()); 257 258 hidl_vec<PowerEntityStateSpace> selectedStateSpaces; 259 getStateSpaces(selectedStateSpaces, randomIds); 260 261 std::map<uint32_t, PowerEntityStateSpace> stateSpaceMap; 262 for (auto stateSpace : stateSpaces) { 263 stateSpaceMap[stateSpace.powerEntityId] = stateSpace; 264 } 265 266 for (auto stateSpace : selectedStateSpaces) { 267 auto it = stateSpaceMap.find(stateSpace.powerEntityId); 268 ASSERT_NE(it, stateSpaceMap.end()); 269 270 ASSERT_EQ(stateSpace.states.size(), it->second.states.size()); 271 for (auto i = 0; i < stateSpace.states.size(); i++) { 272 ASSERT_EQ(stateSpace.states[i].powerEntityStateId, 273 it->second.states[i].powerEntityStateId); 274 ASSERT_EQ(stateSpace.states[i].powerEntityStateName, 275 it->second.states[i].powerEntityStateName); 276 } 277 } 278 } 279 280 // stateResidencyResults must contain results for every PowerEntityStateSpace 281 // returned by getPowerEntityStateInfo 282 TEST_F(PowerStatsHidlTest, ValidateResidencyResultsAssociation) { 283 hidl_vec<PowerEntityStateSpace> stateSpaces; 284 getStateSpaces(stateSpaces); 285 286 hidl_vec<PowerEntityStateResidencyResult> results; 287 getResidencyResults(results); 288 289 std::map<uint32_t, PowerEntityStateResidencyResult> resultsMap; 290 for (auto result : results) { 291 resultsMap[result.powerEntityId] = result; 292 } 293 294 for (auto stateSpace : stateSpaces) { 295 auto it = resultsMap.find(stateSpace.powerEntityId); 296 ASSERT_NE(it, resultsMap.end()); 297 298 ASSERT_EQ(stateSpace.states.size(), it->second.stateResidencyData.size()); 299 300 std::set<uint32_t> stateIds; 301 for (auto residency : it->second.stateResidencyData) { 302 stateIds.insert(residency.powerEntityStateId); 303 } 304 305 for (auto state : stateSpace.states) { 306 ASSERT_NE(stateIds.count(state.powerEntityStateId), 0); 307 } 308 } 309 } 310 311 // getPowerEntityStateResidencyData must support passing in requested IDs 312 // stateResidencyResults must contain results for each PowerEntityStateSpace 313 // returned by getPowerEntityStateInfo 314 TEST_F(PowerStatsHidlTest, ValidateResidencyResultsAssociationSelect) { 315 std::vector<uint32_t> randomIds; 316 getRandomIds(randomIds); 317 if (randomIds.empty()) { 318 return; 319 } 320 321 hidl_vec<PowerEntityStateSpace> stateSpaces; 322 getStateSpaces(stateSpaces, randomIds); 323 324 hidl_vec<PowerEntityStateResidencyResult> results; 325 getResidencyResults(results, randomIds); 326 327 std::map<uint32_t, PowerEntityStateResidencyResult> resultsMap; 328 for (auto result : results) { 329 resultsMap[result.powerEntityId] = result; 330 } 331 332 for (auto stateSpace : stateSpaces) { 333 auto it = resultsMap.find(stateSpace.powerEntityId); 334 ASSERT_NE(it, resultsMap.end()); 335 336 ASSERT_EQ(stateSpace.states.size(), it->second.stateResidencyData.size()); 337 338 std::set<uint32_t> stateIds; 339 for (auto residency : it->second.stateResidencyData) { 340 stateIds.insert(residency.powerEntityStateId); 341 } 342 343 for (auto state : stateSpace.states) { 344 ASSERT_NE(stateIds.count(state.powerEntityStateId), 0); 345 } 346 } 347 } 348 349 TEST_F(PowerStatsHidlTest, ValidateRailInfo) { 350 hidl_vec<RailInfo> rails[2]; 351 Status s; 352 auto cb = [&rails, &s](hidl_vec<RailInfo> rail_subsys, Status status) { 353 rails[0] = rail_subsys; 354 s = status; 355 }; 356 Return<void> ret = service_->getRailInfo(cb); 357 EXPECT_TRUE(ret.isOk()); 358 if (s == Status::SUCCESS) { 359 /* Rails size should be non-zero on SUCCESS*/ 360 ASSERT_NE(rails[0].size(), 0); 361 /* check if indices returned are unique*/ 362 set<uint32_t> ids; 363 for (auto rail : rails[0]) { 364 ASSERT_TRUE(ids.insert(rail.index).second); 365 } 366 auto cb = [&rails, &s](hidl_vec<RailInfo> rail_subsys, Status status) { 367 rails[1] = rail_subsys; 368 s = status; 369 }; 370 Return<void> ret = service_->getRailInfo(cb); 371 EXPECT_TRUE(ret.isOk()); 372 ASSERT_EQ(s, Status::SUCCESS); 373 ASSERT_EQ(rails[0].size(), rails[1].size()); 374 /* check if data returned by two calls to getRailInfo is same*/ 375 for (int i = 0; i < rails[0].size(); i++) { 376 ASSERT_NE(rails[0][i].railName, ""); 377 ASSERT_NE(rails[0][i].subsysName, ""); 378 int j = 0; 379 bool match = false; 380 for (j = 0; j < rails[1].size(); j++) { 381 if (rails[0][i].index == rails[1][j].index) { 382 ASSERT_EQ(rails[0][i].railName, rails[1][i].railName); 383 ASSERT_EQ(rails[0][i].subsysName, rails[1][i].subsysName); 384 match = true; 385 break; 386 } 387 } 388 ASSERT_TRUE(match); 389 } 390 } else if (s == Status::FILESYSTEM_ERROR) { 391 ALOGI("ValidateRailInfo returned FILESYSTEM_ERROR"); 392 ASSERT_EQ(rails[0].size(), 0); 393 } else if (s == Status::NOT_SUPPORTED) { 394 ALOGI("ValidateRailInfo returned NOT_SUPPORTED"); 395 ASSERT_EQ(rails[0].size(), 0); 396 } else if (s == Status::INVALID_INPUT) { 397 ALOGI("ValidateRailInfo returned INVALID_INPUT"); 398 ASSERT_EQ(rails[0].size(), 0); 399 } else if (s == Status::INSUFFICIENT_RESOURCES) { 400 ALOGI("ValidateRailInfo returned INSUFFICIENT_RESOURCES"); 401 ASSERT_EQ(rails[0].size(), 0); 402 } 403 } 404 405 TEST_F(PowerStatsHidlTest, ValidateAllPowerData) { 406 hidl_vec<EnergyData> measurements[2]; 407 Status s; 408 auto cb = [&measurements, &s](hidl_vec<EnergyData> measure, Status status) { 409 measurements[0] = measure; 410 s = status; 411 }; 412 Return<void> ret = service_->getEnergyData(hidl_vec<uint32_t>(), cb); 413 EXPECT_TRUE(ret.isOk()); 414 if (s == Status::SUCCESS) { 415 /*measurements size should be non-zero on SUCCESS*/ 416 ASSERT_NE(measurements[0].size(), 0); 417 auto cb = [&measurements, &s](hidl_vec<EnergyData> measure, Status status) { 418 measurements[1] = measure; 419 s = status; 420 }; 421 Return<void> ret = service_->getEnergyData(hidl_vec<uint32_t>(), cb); 422 EXPECT_TRUE(ret.isOk()); 423 ASSERT_EQ(s, Status::SUCCESS); 424 /*Both calls should returns same amount of data*/ 425 ASSERT_EQ(measurements[0].size(), measurements[1].size()); 426 /*Check is energy and timestamp are monotonically increasing*/ 427 for (int i = 0; i < measurements[0].size(); i++) { 428 int j; 429 for (j = 0; j < measurements[1].size(); j++) { 430 if (measurements[0][i].index == measurements[1][j].index) { 431 EXPECT_GE(measurements[1][j].timestamp, measurements[0][i].timestamp); 432 EXPECT_GE(measurements[1][j].energy, measurements[0][i].energy); 433 break; 434 } 435 } 436 /*Check is indices for two call match*/ 437 ASSERT_NE(j, measurements[1].size()); 438 } 439 } else if (s == Status::FILESYSTEM_ERROR) { 440 ALOGI("ValidateAllPowerData returned FILESYSTEM_ERROR"); 441 ASSERT_EQ(measurements[0].size(), 0); 442 } else if (s == Status::NOT_SUPPORTED) { 443 ALOGI("ValidateAllPowerData returned NOT_SUPPORTED"); 444 ASSERT_EQ(measurements[0].size(), 0); 445 } else if (s == Status::INVALID_INPUT) { 446 ALOGI("ValidateAllPowerData returned INVALID_INPUT"); 447 ASSERT_EQ(measurements[0].size(), 0); 448 } else if (s == Status::INSUFFICIENT_RESOURCES) { 449 ALOGI("ValidateAllPowerData returned INSUFFICIENT_RESOURCES"); 450 ASSERT_EQ(measurements[0].size(), 0); 451 } 452 } 453 454 TEST_F(PowerStatsHidlTest, ValidateFilteredPowerData) { 455 hidl_vec<RailInfo> rails; 456 hidl_vec<EnergyData> measurements; 457 hidl_vec<uint32_t> indices; 458 std::string debugString; 459 Status s; 460 auto cb = [&rails, &s](hidl_vec<RailInfo> rail_subsys, Status status) { 461 rails = rail_subsys; 462 s = status; 463 }; 464 Return<void> ret = service_->getRailInfo(cb); 465 EXPECT_TRUE(ret.isOk()); 466 std::time_t seed = std::time(nullptr); 467 std::srand(seed); 468 if (s == Status::SUCCESS) { 469 size_t sz = std::max(1, (int)(std::rand() % rails.size())); 470 indices.resize(sz); 471 for (int i = 0; i < sz; i++) { 472 int j = std::rand() % rails.size(); 473 indices[i] = rails[j].index; 474 debugString += std::to_string(indices[i]) + ", "; 475 } 476 debugString += "\n"; 477 ALOGI("ValidateFilteredPowerData for indices: %s", debugString.c_str()); 478 auto cb = [&measurements, &s](hidl_vec<EnergyData> measure, Status status) { 479 measurements = measure; 480 s = status; 481 }; 482 Return<void> ret = service_->getEnergyData(indices, cb); 483 EXPECT_TRUE(ret.isOk()); 484 if (s == Status::SUCCESS) { 485 /* Make sure that all the measurements are returned */ 486 ASSERT_EQ(sz, measurements.size()); 487 for (int i = 0; i < measurements.size(); i++) { 488 int j; 489 bool match = false; 490 /* Check that the measurement belongs to the requested index */ 491 for (j = 0; j < indices.size(); j++) { 492 if (indices[j] == measurements[i].index) { 493 match = true; 494 break; 495 } 496 } 497 ASSERT_TRUE(match); 498 } 499 } 500 } else { 501 /* size should be zero is stats is NOT SUCCESS */ 502 ASSERT_EQ(rails.size(), 0); 503 } 504 } 505 506 void readEnergy(sp<IPowerStats> service_, uint32_t timeMs) { 507 std::unique_ptr<MessageQueueSync> mQueue; 508 Status s; 509 uint32_t railsInSample; 510 uint32_t totalSamples; 511 auto cb = [&s, &mQueue, &totalSamples, &railsInSample]( 512 const hardware::MQDescriptorSync<EnergyData>& in, uint32_t numSamples, 513 uint32_t railsPerSample, Status status) { 514 mQueue.reset(new (std::nothrow) MessageQueueSync(in)); 515 s = status; 516 totalSamples = numSamples; 517 railsInSample = railsPerSample; 518 }; 519 service_->streamEnergyData(timeMs, 10, cb); 520 if (s == Status::SUCCESS) { 521 ASSERT_NE(nullptr, mQueue); 522 ASSERT_TRUE(mQueue->isValid()); 523 bool rc; 524 int sampleCount = 0; 525 uint32_t totalQuants = railsInSample * totalSamples; 526 uint64_t timeout_ns = 10000000000; 527 if (totalSamples > 0) { 528 uint32_t batch = std::max(1, (int)((std::rand() % totalSamples) * railsInSample)); 529 ALOGI("Read energy, timsMs: %u, batch: %u", timeMs, batch); 530 std::vector<EnergyData> data(batch); 531 while (sampleCount < totalQuants) { 532 rc = mQueue->readBlocking(&data[0], batch, timeout_ns); 533 if (rc == false) { 534 break; 535 } 536 sampleCount = sampleCount + batch; 537 if (batch > totalQuants - sampleCount) { 538 batch = 1; 539 } 540 } 541 ASSERT_EQ(totalQuants, sampleCount); 542 } 543 } else if (s == Status::FILESYSTEM_ERROR) { 544 ASSERT_FALSE(mQueue->isValid()); 545 ASSERT_EQ(totalSamples, 0); 546 ASSERT_EQ(railsInSample, 0); 547 } else if (s == Status::NOT_SUPPORTED) { 548 ASSERT_FALSE(mQueue->isValid()); 549 ASSERT_EQ(totalSamples, 0); 550 ASSERT_EQ(railsInSample, 0); 551 } else if (s == Status::INVALID_INPUT) { 552 ASSERT_FALSE(mQueue->isValid()); 553 ASSERT_EQ(totalSamples, 0); 554 ASSERT_EQ(railsInSample, 0); 555 } else if (s == Status::INSUFFICIENT_RESOURCES) { 556 ASSERT_FALSE(mQueue->isValid()); 557 ASSERT_EQ(totalSamples, 0); 558 ASSERT_EQ(railsInSample, 0); 559 } 560 } 561 562 TEST_F(PowerStatsHidlTest, StreamEnergyData) { 563 std::time_t seed = std::time(nullptr); 564 std::srand(seed); 565 std::thread thread1 = std::thread(readEnergy, service_, std::rand() % 5000); 566 thread1.join(); 567 } 568 569 } // namespace vts 570 } // namespace stats 571 } // namespace power 572 } // namespace android 573 574 int main(int argc, char** argv) { 575 ::testing::AddGlobalTestEnvironment(android::power::stats::vts::PowerStatsHidlEnv::Instance()); 576 ::testing::InitGoogleTest(&argc, argv); 577 android::power::stats::vts::PowerStatsHidlEnv::Instance()->init(&argc, argv); 578 int status = RUN_ALL_TESTS(); 579 LOG(INFO) << "Test result = " << status; 580 return status; 581 } 582