/** * Copyright (c) 2020, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "CarPowerPolicyServer.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace android { namespace frameworks { namespace automotive { namespace powerpolicy { using android::IBinder; using ::aidl::android::frameworks::automotive::powerpolicy::BnCarPowerPolicyChangeCallback; using ::aidl::android::frameworks::automotive::powerpolicy::CarPowerPolicy; using ::aidl::android::frameworks::automotive::powerpolicy::CarPowerPolicyFilter; using ::aidl::android::frameworks::automotive::powerpolicy::ICarPowerPolicyChangeCallback; using ::aidl::android::frameworks::automotive::powerpolicy::ICarPowerPolicyServer; using ::aidl::android::frameworks::automotive::powerpolicy::PowerComponent; using ::ndk::ScopedAStatus; using ::ndk::SpAIBinder; using ::testing::_; using ::testing::Invoke; using ::testing::Return; namespace { class MockPowerPolicyChangeCallback : public BnCarPowerPolicyChangeCallback { public: ScopedAStatus onPolicyChanged(const CarPowerPolicy& /*policy*/) override { return ScopedAStatus::ok(); } }; } // namespace namespace internal { class CarPowerPolicyServerPeer : public RefBase { public: CarPowerPolicyServerPeer() { std::unique_ptr impl = std::make_unique(); // We know this would be alive as long as server is alive. mLinkUnlinkImpl = impl.get(); mServer = ::ndk::SharedRefBase::make(); mServer->setLinkUnlinkImpl(std::move(impl)); mBinder = mServer->asBinder(); mServerProxy = ICarPowerPolicyServer::fromBinder(mBinder); } ScopedAStatus getCurrentPowerPolicy(CarPowerPolicy* aidlReturn) { return mServerProxy->getCurrentPowerPolicy(aidlReturn); } ScopedAStatus registerPowerPolicyChangeCallback( const std::shared_ptr& callback, const CarPowerPolicyFilter& filter) { return mServerProxy->registerPowerPolicyChangeCallback(callback, filter); } ScopedAStatus unregisterPowerPolicyChangeCallback( const std::shared_ptr& callback) { return mServerProxy->unregisterPowerPolicyChangeCallback(callback); } void onBinderDied(void* cookie) { mServer->onBinderDied(cookie); } std::vector getPolicyChangeCallbacks() { return mServer->getPolicyChangeCallbacks(); } size_t countOnBinderDiedContexts() { return mServer->countOnBinderDiedContexts(); } std::unordered_set getCookies() { return mLinkUnlinkImpl->getCookies(); } void expectLinkToDeathStatus(AIBinder* binder, status_t linkToDeathResult) { mLinkUnlinkImpl->expectLinkToDeathStatus(binder, linkToDeathResult); } private: class MockLinkUnlinkImpl : public CarPowerPolicyServer::LinkUnlinkImpl { public: MOCK_METHOD(binder_status_t, linkToDeath, (AIBinder*, AIBinder_DeathRecipient*, void*), (override)); MOCK_METHOD(binder_status_t, unlinkToDeath, (AIBinder*, AIBinder_DeathRecipient*, void*), (override)); void expectLinkToDeathStatus(AIBinder* binder, binder_status_t linkToDeathResult) { EXPECT_CALL(*this, linkToDeath(binder, _, _)) .WillRepeatedly( Invoke([this, linkToDeathResult](AIBinder*, AIBinder_DeathRecipient*, void* cookie) { Mutex::Autolock lock(mMutex); mCookies.insert(cookie); return linkToDeathResult; })); EXPECT_CALL(*this, unlinkToDeath(binder, _, _)) .WillRepeatedly( Invoke([this](AIBinder*, AIBinder_DeathRecipient*, void* cookie) { Mutex::Autolock lock(mMutex); mCookies.erase(cookie); return STATUS_OK; })); } std::unordered_set getCookies() { Mutex::Autolock lock(mMutex); return mCookies; } private: android::Mutex mMutex; std::unordered_set mCookies GUARDED_BY(mMutex); }; MockLinkUnlinkImpl* mLinkUnlinkImpl; std::shared_ptr mServer; std::shared_ptr mServerProxy; SpAIBinder mBinder; }; } // namespace internal class CarPowerPolicyServerTest : public ::testing::Test { public: std::shared_ptr getPowerPolicyChangeCallback() { std::shared_ptr callback = ndk::SharedRefBase::make(); return ICarPowerPolicyChangeCallback::fromBinder(callback->asBinder()); } }; TEST_F(CarPowerPolicyServerTest, TestRegisterCallback) { sp server = new internal::CarPowerPolicyServerPeer(); std::shared_ptr callbackOne = getPowerPolicyChangeCallback(); server->expectLinkToDeathStatus(callbackOne->asBinder().get(), STATUS_OK); CarPowerPolicyFilter filter; ScopedAStatus status = server->registerPowerPolicyChangeCallback(callbackOne, filter); ASSERT_TRUE(status.isOk()) << status.getMessage(); status = server->registerPowerPolicyChangeCallback(callbackOne, filter); ASSERT_FALSE(status.isOk()) << "Duplicated registration is not allowed"; filter.components = {PowerComponent::BLUETOOTH, PowerComponent::AUDIO}; status = server->registerPowerPolicyChangeCallback(callbackOne, filter); ASSERT_FALSE(status.isOk()) << "Duplicated registration is not allowed"; std::shared_ptr callbackTwo = getPowerPolicyChangeCallback(); server->expectLinkToDeathStatus(callbackTwo->asBinder().get(), STATUS_OK); status = server->registerPowerPolicyChangeCallback(callbackTwo, filter); ASSERT_TRUE(status.isOk()) << status.getMessage(); } TEST_F(CarPowerPolicyServerTest, TestRegisterCallback_BinderDied) { sp server = new internal::CarPowerPolicyServerPeer(); std::shared_ptr callback = getPowerPolicyChangeCallback(); server->expectLinkToDeathStatus(callback->asBinder().get(), STATUS_DEAD_OBJECT); CarPowerPolicyFilter filter; ASSERT_FALSE(server->registerPowerPolicyChangeCallback(callback, filter).isOk()) << "When linkToDeath fails, registerPowerPolicyChangeCallback should return an error"; } TEST_F(CarPowerPolicyServerTest, TestOnBinderDied) { sp server = new internal::CarPowerPolicyServerPeer(); std::shared_ptr callbackOne = getPowerPolicyChangeCallback(); server->expectLinkToDeathStatus(callbackOne->asBinder().get(), STATUS_OK); CarPowerPolicyFilter filter; ScopedAStatus status = server->registerPowerPolicyChangeCallback(callbackOne, filter); ASSERT_TRUE(status.isOk()) << status.getMessage(); ASSERT_EQ(server->getPolicyChangeCallbacks().size(), static_cast(1)); ASSERT_EQ(server->countOnBinderDiedContexts(), static_cast(1)); ASSERT_EQ(server->getCookies().size(), static_cast(1)); void* cookie = *(server->getCookies().begin()); server->onBinderDied(cookie); ASSERT_TRUE(server->getPolicyChangeCallbacks().empty()); ASSERT_EQ(server->countOnBinderDiedContexts(), static_cast(0)); } TEST_F(CarPowerPolicyServerTest, TestUnregisterCallback) { sp server = new internal::CarPowerPolicyServerPeer(); std::shared_ptr callback = getPowerPolicyChangeCallback(); server->expectLinkToDeathStatus(callback->asBinder().get(), STATUS_OK); CarPowerPolicyFilter filter; server->registerPowerPolicyChangeCallback(callback, filter); ScopedAStatus status = server->unregisterPowerPolicyChangeCallback(callback); ASSERT_TRUE(status.isOk()) << status.getMessage(); ASSERT_FALSE(server->unregisterPowerPolicyChangeCallback(callback).isOk()) << "Unregistering an unregistered powerpolicy change callback should return an error"; } TEST_F(CarPowerPolicyServerTest, TestGetCurrentPowerPolicy) { sp server = new internal::CarPowerPolicyServerPeer(); CarPowerPolicy currentPolicy; ScopedAStatus status = server->getCurrentPowerPolicy(¤tPolicy); ASSERT_FALSE(status.isOk()) << "The current policy at creation should be null"; // TODO(b/168545262): Add more test cases after VHAL integration is complete. } } // namespace powerpolicy } // namespace automotive } // namespace frameworks } // namespace android