Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ef92a94 authored by Yu Shan's avatar Yu Shan Committed by Android (Google) Code Review
Browse files

Merge "Migrate fake value generator hub."

parents a4865ca5 7987654e
Loading
Loading
Loading
Loading
+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",
    ],
}
+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_
+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_
+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
+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