Loading automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h +34 −0 Original line number Diff line number Diff line Loading @@ -190,6 +190,40 @@ const std::vector<ConfigDeclaration> kVehicleProperties = { }, .initialValue = {.int32Values = {toInt(VehicleUnit::KILOWATT_HOUR)}}}, {.config = {.prop = toInt(VehicleProperty::SEAT_MEMORY_SELECT), .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_2_LEFT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 3}}}, .initialValue = {.int32Values = {1}}}, {.config = {.prop = toInt(VehicleProperty::SEAT_MEMORY_SET), .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_2_LEFT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 3}}}, .initialValue = {.int32Values = {1}}}, {.config = {.prop = toInt(VehicleProperty::SEAT_BELT_BUCKLED), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, Loading automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h +3 −2 Original line number Diff line number Diff line Loading @@ -83,8 +83,9 @@ class RecurrentTimer final { // each time we might introduce outdated elements to the top. We must make sure the heap is // always valid from the top. void removeInvalidCallbackLocked() REQUIRES(mLock); // Pops the next closest callback (must be valid) from the heap. std::unique_ptr<CallbackInfo> popNextCallbackLocked() REQUIRES(mLock); // Gets the next calblack to run (must be valid) from the heap, update its nextTime and put // it back to the heap. std::shared_ptr<Callback> getNextCallbackLocked(int64_t now) REQUIRES(mLock); }; } // namespace vehicle Loading automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp +35 −32 Original line number Diff line number Diff line Loading @@ -101,19 +101,27 @@ void RecurrentTimer::removeInvalidCallbackLocked() { } } std::unique_ptr<RecurrentTimer::CallbackInfo> RecurrentTimer::popNextCallbackLocked() { std::shared_ptr<RecurrentTimer::Callback> RecurrentTimer::getNextCallbackLocked(int64_t now) { std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp); std::unique_ptr<CallbackInfo> info = std::move(mCallbackQueue[mCallbackQueue.size() - 1]); mCallbackQueue.pop_back(); auto& callbackInfo = mCallbackQueue[mCallbackQueue.size() - 1]; auto nextCallback = callbackInfo->callback; // intervalCount is the number of interval we have to advance until we pass now. size_t intervalCount = (now - callbackInfo->nextTime) / callbackInfo->interval + 1; callbackInfo->nextTime += intervalCount * callbackInfo->interval; std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp); // Make sure the first element is always valid. removeInvalidCallbackLocked(); return info; return nextCallback; } void RecurrentTimer::loop() { std::unique_lock<std::mutex> uniqueLock(mLock); std::vector<std::shared_ptr<Callback>> callbacksToRun; while (true) { { std::unique_lock<std::mutex> uniqueLock(mLock); ScopedLockAssertion lockAssertion(mLock); // Wait until the timer exits or we have at least one recurrent callback. mCond.wait(uniqueLock, [this] { ScopedLockAssertion lockAssertion(mLock); Loading @@ -121,20 +129,18 @@ void RecurrentTimer::loop() { }); int64_t interval; { ScopedLockAssertion lockAssertion(mLock); if (mStopRequested) { return; } // The first element is the nearest next event. int64_t nextTime = mCallbackQueue[0]->nextTime; int64_t now = uptimeNanos(); if (nextTime > now) { interval = nextTime - now; } else { interval = 0; } } // Wait for the next event or the timer exits. if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] { Loading @@ -144,25 +150,22 @@ void RecurrentTimer::loop() { return; } { ScopedLockAssertion lockAssertion(mLock); int64_t now = uptimeNanos(); now = uptimeNanos(); callbacksToRun.clear(); while (mCallbackQueue.size() > 0) { int64_t nextTime = mCallbackQueue[0]->nextTime; if (nextTime > now) { break; } std::unique_ptr<CallbackInfo> info = popNextCallbackLocked(); info->nextTime += info->interval; auto callback = info->callback; mCallbackQueue.push_back(std::move(info)); std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp); (*callback)(); callbacksToRun.push_back(getNextCallbackLocked(now)); } } // Do not execute the callback while holding the lock. for (size_t i = 0; i < callbacksToRun.size(); i++) { (*callbacksToRun[i])(); } } } Loading automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -186,6 +186,33 @@ TEST_F(RecurrentTimerTest, testRegisterSameCallbackMultipleTimes) { ASSERT_EQ(countTimerCallbackQueue(&timer), static_cast<size_t>(0)); } TEST_F(RecurrentTimerTest, testRegisterCallbackMultipleTimesNoDeadLock) { // We want to avoid the following situation: // Caller holds a lock while calling registerTimerCallback, registerTimerCallback will try // to obtain an internal lock inside timer. // Meanwhile an recurrent action happens with timer holding an internal lock. The action // tries to obtain the lock currently hold by the caller. // The solution is that while calling recurrent actions, timer must not hold the internal lock. std::unique_ptr<RecurrentTimer> timer = std::make_unique<RecurrentTimer>(); std::mutex lock; for (size_t i = 0; i < 1000; i++) { std::scoped_lock<std::mutex> lockGuard(lock); auto action = std::make_shared<RecurrentTimer::Callback>([&lock] { // While calling this function, the timer must not hold lock in order not to dead // lock. std::scoped_lock<std::mutex> lockGuard(lock); }); // 10ms int64_t interval = 10'000'000; timer->registerTimerCallback(interval, action); // Sleep for a little while to let the recurrent actions begin. std::this_thread::sleep_for(std::chrono::milliseconds(1)); } // Make sure we stop the timer before we destroy lock. timer.reset(); } } // namespace vehicle } // namespace automotive } // namespace hardware Loading gnss/aidl/default/Gnss.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -68,7 +68,7 @@ ScopedAStatus Gnss::setCallback(const std::shared_ptr<IGnssCallback>& callback) IGnssCallback::GnssSystemInfo systemInfo = { .yearOfHw = 2022, .name = "Google Mock GNSS Implementation AIDL v2", .name = "Google, Cuttlefish, AIDL v2", }; status = sGnssCallback->gnssSetSystemInfoCb(systemInfo); if (!status.isOk()) { Loading Loading
automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h +34 −0 Original line number Diff line number Diff line Loading @@ -190,6 +190,40 @@ const std::vector<ConfigDeclaration> kVehicleProperties = { }, .initialValue = {.int32Values = {toInt(VehicleUnit::KILOWATT_HOUR)}}}, {.config = {.prop = toInt(VehicleProperty::SEAT_MEMORY_SELECT), .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_2_LEFT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 3}}}, .initialValue = {.int32Values = {1}}}, {.config = {.prop = toInt(VehicleProperty::SEAT_MEMORY_SET), .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_2_LEFT, .minInt32Value = 0, .maxInt32Value = 3}, VehicleAreaConfig{.areaId = SEAT_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 3}}}, .initialValue = {.int32Values = {1}}}, {.config = {.prop = toInt(VehicleProperty::SEAT_BELT_BUCKLED), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, Loading
automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h +3 −2 Original line number Diff line number Diff line Loading @@ -83,8 +83,9 @@ class RecurrentTimer final { // each time we might introduce outdated elements to the top. We must make sure the heap is // always valid from the top. void removeInvalidCallbackLocked() REQUIRES(mLock); // Pops the next closest callback (must be valid) from the heap. std::unique_ptr<CallbackInfo> popNextCallbackLocked() REQUIRES(mLock); // Gets the next calblack to run (must be valid) from the heap, update its nextTime and put // it back to the heap. std::shared_ptr<Callback> getNextCallbackLocked(int64_t now) REQUIRES(mLock); }; } // namespace vehicle Loading
automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp +35 −32 Original line number Diff line number Diff line Loading @@ -101,19 +101,27 @@ void RecurrentTimer::removeInvalidCallbackLocked() { } } std::unique_ptr<RecurrentTimer::CallbackInfo> RecurrentTimer::popNextCallbackLocked() { std::shared_ptr<RecurrentTimer::Callback> RecurrentTimer::getNextCallbackLocked(int64_t now) { std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp); std::unique_ptr<CallbackInfo> info = std::move(mCallbackQueue[mCallbackQueue.size() - 1]); mCallbackQueue.pop_back(); auto& callbackInfo = mCallbackQueue[mCallbackQueue.size() - 1]; auto nextCallback = callbackInfo->callback; // intervalCount is the number of interval we have to advance until we pass now. size_t intervalCount = (now - callbackInfo->nextTime) / callbackInfo->interval + 1; callbackInfo->nextTime += intervalCount * callbackInfo->interval; std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp); // Make sure the first element is always valid. removeInvalidCallbackLocked(); return info; return nextCallback; } void RecurrentTimer::loop() { std::unique_lock<std::mutex> uniqueLock(mLock); std::vector<std::shared_ptr<Callback>> callbacksToRun; while (true) { { std::unique_lock<std::mutex> uniqueLock(mLock); ScopedLockAssertion lockAssertion(mLock); // Wait until the timer exits or we have at least one recurrent callback. mCond.wait(uniqueLock, [this] { ScopedLockAssertion lockAssertion(mLock); Loading @@ -121,20 +129,18 @@ void RecurrentTimer::loop() { }); int64_t interval; { ScopedLockAssertion lockAssertion(mLock); if (mStopRequested) { return; } // The first element is the nearest next event. int64_t nextTime = mCallbackQueue[0]->nextTime; int64_t now = uptimeNanos(); if (nextTime > now) { interval = nextTime - now; } else { interval = 0; } } // Wait for the next event or the timer exits. if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] { Loading @@ -144,25 +150,22 @@ void RecurrentTimer::loop() { return; } { ScopedLockAssertion lockAssertion(mLock); int64_t now = uptimeNanos(); now = uptimeNanos(); callbacksToRun.clear(); while (mCallbackQueue.size() > 0) { int64_t nextTime = mCallbackQueue[0]->nextTime; if (nextTime > now) { break; } std::unique_ptr<CallbackInfo> info = popNextCallbackLocked(); info->nextTime += info->interval; auto callback = info->callback; mCallbackQueue.push_back(std::move(info)); std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp); (*callback)(); callbacksToRun.push_back(getNextCallbackLocked(now)); } } // Do not execute the callback while holding the lock. for (size_t i = 0; i < callbacksToRun.size(); i++) { (*callbacksToRun[i])(); } } } Loading
automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -186,6 +186,33 @@ TEST_F(RecurrentTimerTest, testRegisterSameCallbackMultipleTimes) { ASSERT_EQ(countTimerCallbackQueue(&timer), static_cast<size_t>(0)); } TEST_F(RecurrentTimerTest, testRegisterCallbackMultipleTimesNoDeadLock) { // We want to avoid the following situation: // Caller holds a lock while calling registerTimerCallback, registerTimerCallback will try // to obtain an internal lock inside timer. // Meanwhile an recurrent action happens with timer holding an internal lock. The action // tries to obtain the lock currently hold by the caller. // The solution is that while calling recurrent actions, timer must not hold the internal lock. std::unique_ptr<RecurrentTimer> timer = std::make_unique<RecurrentTimer>(); std::mutex lock; for (size_t i = 0; i < 1000; i++) { std::scoped_lock<std::mutex> lockGuard(lock); auto action = std::make_shared<RecurrentTimer::Callback>([&lock] { // While calling this function, the timer must not hold lock in order not to dead // lock. std::scoped_lock<std::mutex> lockGuard(lock); }); // 10ms int64_t interval = 10'000'000; timer->registerTimerCallback(interval, action); // Sleep for a little while to let the recurrent actions begin. std::this_thread::sleep_for(std::chrono::milliseconds(1)); } // Make sure we stop the timer before we destroy lock. timer.reset(); } } // namespace vehicle } // namespace automotive } // namespace hardware Loading
gnss/aidl/default/Gnss.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -68,7 +68,7 @@ ScopedAStatus Gnss::setCallback(const std::shared_ptr<IGnssCallback>& callback) IGnssCallback::GnssSystemInfo systemInfo = { .yearOfHw = 2022, .name = "Google Mock GNSS Implementation AIDL v2", .name = "Google, Cuttlefish, AIDL v2", }; status = sGnssCallback->gnssSetSystemInfoCb(systemInfo); if (!status.isOk()) { Loading