Loading automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp 0 → 100644 +32 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ package { default_applicable_licenses: ["Android-Apache-2.0"], } cc_library { name: "FakeVehicleHalValueGenerators", vendor: true, srcs: ["src/*.cpp"], local_include_dirs: ["include"], export_include_dirs: ["include"], defaults: ["VehicleHalDefaults"], static_libs: ["VehicleHalUtils"], shared_libs: [ "libjsoncpp", ], } automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/FakeValueGenerator.h 0 → 100644 +46 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ #ifndef android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_FakeValueGenerator_H_ #define android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_FakeValueGenerator_H_ #include <VehicleHalTypes.h> #include <optional> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { // A abstract class for all fake value generators. class FakeValueGenerator { public: virtual ~FakeValueGenerator() = default; // Returns the next event if there is one or {@code std::nullopt} if there is none. virtual std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> nextEvent() = 0; }; } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android #endif // android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_FakeValueGenerator_H_ automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/GeneratorHub.h 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ #ifndef android_hardware_interfaces_automotive_vehicle_aidl_fake_impl_GeneratorHub_include_GeneratorHub_h_ #define android_hardware_interfaces_automotive_vehicle_aidl_fake_impl_GeneratorHub_include_GeneratorHub_h_ #include "FakeValueGenerator.h" #include <android-base/thread_annotations.h> #include <atomic> #include <chrono> #include <condition_variable> #include <iostream> #include <mutex> #include <optional> #include <queue> #include <thread> #include <unordered_map> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { // This is the scheduler for all VHAL event generators. It manages all generators and uses priority // queue to maintain generated events ordered by timestamp. The scheduler uses a single thread to // keep querying and updating the event queue to make sure events from all generators are produced // in order. class GeneratorHub { public: using OnHalEvent = std::function<void( const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& event)>; explicit GeneratorHub(OnHalEvent&& onHalEvent); ~GeneratorHub(); // Register a new generator. The generator will be discarded if it could not produce next event. // The existing generator will be overridden if it has the same generatorId. void registerGenerator(int32_t generatorId, std::unique_ptr<FakeValueGenerator> generator); // Unregister a generator with the generatorId. If no registered generator is found, this // function does nothing. void unregisterGenerator(int32_t generatorId); private: struct VhalEvent { int32_t generatorId; ::aidl::android::hardware::automotive::vehicle::VehiclePropValue val; }; // Comparator used by priority queue to keep track of soonest event. struct GreaterByTime { bool operator()(const VhalEvent& lhs, const VhalEvent& rhs) const { return lhs.val.timestamp > rhs.val.timestamp; } }; std::priority_queue<VhalEvent, std::vector<VhalEvent>, GreaterByTime> mEventQueue; std::mutex mGeneratorsLock; std::unordered_map<int32_t, std::unique_ptr<FakeValueGenerator>> mGenerators GUARDED_BY(mGeneratorsLock); OnHalEvent mOnHalEvent; std::condition_variable mCond; std::thread mThread; std::atomic<bool> mShuttingDownFlag{false}; // Main loop of the single thread to producing event and updating event queue. void run(); }; } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android #endif // android_hardware_interfaces_automotive_vehicle_aidl_fake_impl_GeneratorHub_include_GeneratorHub_h_ automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/GeneratorHub.cpp 0 → 100644 +123 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ #define LOG_TAG "GeneratorHub" #include "GeneratorHub.h" #include <utils/Log.h> #include <utils/SystemClock.h> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { using ::android::base::ScopedLockAssertion; GeneratorHub::GeneratorHub(OnHalEvent&& onHalEvent) : mOnHalEvent(onHalEvent), mThread(&GeneratorHub::run, this) {} GeneratorHub::~GeneratorHub() { mShuttingDownFlag.store(true); mCond.notify_all(); if (mThread.joinable()) { mThread.join(); } } void GeneratorHub::registerGenerator(int32_t id, std::unique_ptr<FakeValueGenerator> generator) { { std::scoped_lock<std::mutex> lockGuard(mGeneratorsLock); auto maybeNextEvent = generator->nextEvent(); // Register only if the generator can produce at least one event. if (maybeNextEvent.has_value()) { // Push the next event if it is a new generator if (mGenerators.find(id) == mGenerators.end()) { ALOGI("%s: Registering new generator, id: %d", __func__, id); mEventQueue.push({id, maybeNextEvent.value()}); } mGenerators[id] = std::move(generator); ALOGI("%s: Registered generator, id: %d", __func__, id); } } mCond.notify_one(); } void GeneratorHub::unregisterGenerator(int32_t id) { { std::scoped_lock<std::mutex> lockGuard(mGeneratorsLock); mGenerators.erase(id); } mCond.notify_one(); ALOGI("%s: Unregistered generator, id: %d", __func__, id); } void GeneratorHub::run() { while (!mShuttingDownFlag.load()) { std::unique_lock<std::mutex> lock(mGeneratorsLock); ScopedLockAssertion lock_assertion(mGeneratorsLock); // Pop events whose generator does not exist (may be already unregistered) while (!mEventQueue.empty() && mGenerators.find(mEventQueue.top().generatorId) == mGenerators.end()) { mEventQueue.pop(); } // Wait until event queue is not empty or shutting down flag is set. // This would unlock mGeneratorsLock and reacquire later. mCond.wait(lock, [this] { return !mEventQueue.empty() || mShuttingDownFlag.load(); }); if (mShuttingDownFlag.load()) { break; } const VhalEvent& curEvent = mEventQueue.top(); long currentTime = elapsedRealtimeNano(); long waitTime = curEvent.val.timestamp > currentTime ? curEvent.val.timestamp - currentTime : 0; if (waitTime != 0) { // Wait until the soonest event happen if (mCond.wait_for(lock, std::chrono::nanoseconds(waitTime)) != std::cv_status::timeout) { // It is possible that a new generator is registered and produced a sooner event, or // current generator is unregistered, in this case the thread will re-evaluate the // soonest event ALOGI("Something happened while waiting"); continue; } } // Now it's time to handle current event. mOnHalEvent(curEvent.val); // Update queue by popping current event and producing next event from the same generator int32_t id = curEvent.generatorId; mEventQueue.pop(); if (mGenerators.find(id) != mGenerators.end()) { auto maybeNextEvent = mGenerators[id]->nextEvent(); if (maybeNextEvent.has_value()) { mEventQueue.push({id, maybeNextEvent.value()}); continue; } } ALOGI("%s: Generator ended, unregister it, id: %d", __func__, id); mGenerators.erase(id); } } } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp 0 → 100644 +31 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ package { default_applicable_licenses: ["Android-Apache-2.0"], } cc_test { name: "FakeVehicleHalValueGeneratorsTest", vendor: true, srcs: ["*.cpp"], defaults: ["VehicleHalDefaults"], static_libs: [ "VehicleHalUtils", "FakeVehicleHalValueGenerators", ], test_suites: ["device-tests"], } Loading
automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp 0 → 100644 +32 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ package { default_applicable_licenses: ["Android-Apache-2.0"], } cc_library { name: "FakeVehicleHalValueGenerators", vendor: true, srcs: ["src/*.cpp"], local_include_dirs: ["include"], export_include_dirs: ["include"], defaults: ["VehicleHalDefaults"], static_libs: ["VehicleHalUtils"], shared_libs: [ "libjsoncpp", ], }
automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/FakeValueGenerator.h 0 → 100644 +46 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ #ifndef android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_FakeValueGenerator_H_ #define android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_FakeValueGenerator_H_ #include <VehicleHalTypes.h> #include <optional> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { // A abstract class for all fake value generators. class FakeValueGenerator { public: virtual ~FakeValueGenerator() = default; // Returns the next event if there is one or {@code std::nullopt} if there is none. virtual std::optional<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> nextEvent() = 0; }; } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android #endif // android_hardware_automotive_vehicle_aidl_impl_fake_impl_GeneratorHub_include_FakeValueGenerator_H_
automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/GeneratorHub.h 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ #ifndef android_hardware_interfaces_automotive_vehicle_aidl_fake_impl_GeneratorHub_include_GeneratorHub_h_ #define android_hardware_interfaces_automotive_vehicle_aidl_fake_impl_GeneratorHub_include_GeneratorHub_h_ #include "FakeValueGenerator.h" #include <android-base/thread_annotations.h> #include <atomic> #include <chrono> #include <condition_variable> #include <iostream> #include <mutex> #include <optional> #include <queue> #include <thread> #include <unordered_map> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { // This is the scheduler for all VHAL event generators. It manages all generators and uses priority // queue to maintain generated events ordered by timestamp. The scheduler uses a single thread to // keep querying and updating the event queue to make sure events from all generators are produced // in order. class GeneratorHub { public: using OnHalEvent = std::function<void( const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& event)>; explicit GeneratorHub(OnHalEvent&& onHalEvent); ~GeneratorHub(); // Register a new generator. The generator will be discarded if it could not produce next event. // The existing generator will be overridden if it has the same generatorId. void registerGenerator(int32_t generatorId, std::unique_ptr<FakeValueGenerator> generator); // Unregister a generator with the generatorId. If no registered generator is found, this // function does nothing. void unregisterGenerator(int32_t generatorId); private: struct VhalEvent { int32_t generatorId; ::aidl::android::hardware::automotive::vehicle::VehiclePropValue val; }; // Comparator used by priority queue to keep track of soonest event. struct GreaterByTime { bool operator()(const VhalEvent& lhs, const VhalEvent& rhs) const { return lhs.val.timestamp > rhs.val.timestamp; } }; std::priority_queue<VhalEvent, std::vector<VhalEvent>, GreaterByTime> mEventQueue; std::mutex mGeneratorsLock; std::unordered_map<int32_t, std::unique_ptr<FakeValueGenerator>> mGenerators GUARDED_BY(mGeneratorsLock); OnHalEvent mOnHalEvent; std::condition_variable mCond; std::thread mThread; std::atomic<bool> mShuttingDownFlag{false}; // Main loop of the single thread to producing event and updating event queue. void run(); }; } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android #endif // android_hardware_interfaces_automotive_vehicle_aidl_fake_impl_GeneratorHub_include_GeneratorHub_h_
automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/GeneratorHub.cpp 0 → 100644 +123 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ #define LOG_TAG "GeneratorHub" #include "GeneratorHub.h" #include <utils/Log.h> #include <utils/SystemClock.h> namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace fake { using ::android::base::ScopedLockAssertion; GeneratorHub::GeneratorHub(OnHalEvent&& onHalEvent) : mOnHalEvent(onHalEvent), mThread(&GeneratorHub::run, this) {} GeneratorHub::~GeneratorHub() { mShuttingDownFlag.store(true); mCond.notify_all(); if (mThread.joinable()) { mThread.join(); } } void GeneratorHub::registerGenerator(int32_t id, std::unique_ptr<FakeValueGenerator> generator) { { std::scoped_lock<std::mutex> lockGuard(mGeneratorsLock); auto maybeNextEvent = generator->nextEvent(); // Register only if the generator can produce at least one event. if (maybeNextEvent.has_value()) { // Push the next event if it is a new generator if (mGenerators.find(id) == mGenerators.end()) { ALOGI("%s: Registering new generator, id: %d", __func__, id); mEventQueue.push({id, maybeNextEvent.value()}); } mGenerators[id] = std::move(generator); ALOGI("%s: Registered generator, id: %d", __func__, id); } } mCond.notify_one(); } void GeneratorHub::unregisterGenerator(int32_t id) { { std::scoped_lock<std::mutex> lockGuard(mGeneratorsLock); mGenerators.erase(id); } mCond.notify_one(); ALOGI("%s: Unregistered generator, id: %d", __func__, id); } void GeneratorHub::run() { while (!mShuttingDownFlag.load()) { std::unique_lock<std::mutex> lock(mGeneratorsLock); ScopedLockAssertion lock_assertion(mGeneratorsLock); // Pop events whose generator does not exist (may be already unregistered) while (!mEventQueue.empty() && mGenerators.find(mEventQueue.top().generatorId) == mGenerators.end()) { mEventQueue.pop(); } // Wait until event queue is not empty or shutting down flag is set. // This would unlock mGeneratorsLock and reacquire later. mCond.wait(lock, [this] { return !mEventQueue.empty() || mShuttingDownFlag.load(); }); if (mShuttingDownFlag.load()) { break; } const VhalEvent& curEvent = mEventQueue.top(); long currentTime = elapsedRealtimeNano(); long waitTime = curEvent.val.timestamp > currentTime ? curEvent.val.timestamp - currentTime : 0; if (waitTime != 0) { // Wait until the soonest event happen if (mCond.wait_for(lock, std::chrono::nanoseconds(waitTime)) != std::cv_status::timeout) { // It is possible that a new generator is registered and produced a sooner event, or // current generator is unregistered, in this case the thread will re-evaluate the // soonest event ALOGI("Something happened while waiting"); continue; } } // Now it's time to handle current event. mOnHalEvent(curEvent.val); // Update queue by popping current event and producing next event from the same generator int32_t id = curEvent.generatorId; mEventQueue.pop(); if (mGenerators.find(id) != mGenerators.end()) { auto maybeNextEvent = mGenerators[id]->nextEvent(); if (maybeNextEvent.has_value()) { mEventQueue.push({id, maybeNextEvent.value()}); continue; } } ALOGI("%s: Generator ended, unregister it, id: %d", __func__, id); mGenerators.erase(id); } } } // namespace fake } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android
automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp 0 → 100644 +31 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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. */ package { default_applicable_licenses: ["Android-Apache-2.0"], } cc_test { name: "FakeVehicleHalValueGeneratorsTest", vendor: true, srcs: ["*.cpp"], defaults: ["VehicleHalDefaults"], static_libs: [ "VehicleHalUtils", "FakeVehicleHalValueGenerators", ], test_suites: ["device-tests"], }