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

Commit 336c1c71 authored by Stan Rokita's avatar Stan Rokita
Browse files

MH2 | Add restart logic in HalProxy::initialize method.

Bug: 136511617
Test: None yet

Change-Id: I389a7243d3612586aae4e8a802afda92af8dcc6d
parent c325670c
Loading
Loading
Loading
Loading
+64 −19
Original line number Diff line number Diff line
@@ -65,15 +65,7 @@ HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHa
}

HalProxy::~HalProxy() {
    mThreadsRun.store(false);
    mWakelockCV.notify_one();
    mEventQueueWriteCV.notify_one();
    if (mPendingWritesThread.joinable()) {
        mPendingWritesThread.join();
    }
    if (mWakelockThread.joinable()) {
        mWakelockThread.join();
    }
    stopThreads();
}

Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
@@ -119,8 +111,18 @@ Return<Result> HalProxy::initialize(
        const sp<ISensorsCallback>& sensorsCallback) {
    Result result = Result::OK;

    // TODO: clean up sensor requests, if not already done elsewhere through a death recipient, and
    // clean up any other resources that exist (FMQs, flags, threads, etc.)
    stopThreads();
    resetSharedWakelock();

    // So that the pending write events queue can be cleared safely and when we start threads
    // again we do not get new events until after initialize resets the subhals.
    disableAllSensors();

    // Clears the queue if any events were pending write before.
    mPendingWriteEventsQueue = std::queue<std::pair<std::vector<Event>, size_t>>();

    // Clears previously connected dynamic sensors
    mDynamicSensors.clear();

    mDynamicSensorsCallback = sensorsCallback;

@@ -128,21 +130,29 @@ Return<Result> HalProxy::initialize(
    mEventQueue =
            std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);

    // Create the EventFlag that is used to signal to the framework that sensor events have been
    // written to the Event FMQ
    if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
        result = Result::BAD_VALUE;
    }

    // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
    // events have been successfully read and handled by the framework.
    mWakeLockQueue =
            std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);

    if (mEventQueueFlag != nullptr) {
        EventFlag::deleteEventFlag(&mEventQueueFlag);
    }
    if (mWakelockQueueFlag != nullptr) {
        EventFlag::deleteEventFlag(&mWakelockQueueFlag);
    }
    if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
        result = Result::BAD_VALUE;
    }
    if (EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakelockQueueFlag) != OK) {
        result = Result::BAD_VALUE;
    }
    if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
        result = Result::BAD_VALUE;
    }

    mThreadsRun.store(true);

    mPendingWritesThread = std::thread(startPendingWritesThread, this);
    mWakelockThread = std::thread(startWakelockThread, this);

@@ -157,6 +167,8 @@ Return<Result> HalProxy::initialize(
        }
    }

    mCurrentOperationMode = OperationMode::NORMAL;

    return result;
}

@@ -331,6 +343,41 @@ void HalProxy::init() {
    initializeSensorList();
}

void HalProxy::stopThreads() {
    mThreadsRun.store(false);
    if (mEventQueueFlag != nullptr && mEventQueue != nullptr) {
        size_t numToRead = mEventQueue->availableToRead();
        std::vector<Event> events(numToRead);
        mEventQueue->read(events.data(), numToRead);
        mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ));
    }
    if (mWakelockQueueFlag != nullptr && mWakeLockQueue != nullptr) {
        uint32_t kZero = 0;
        mWakeLockQueue->write(&kZero);
        mWakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
    }
    mWakelockCV.notify_one();
    mEventQueueWriteCV.notify_one();
    if (mPendingWritesThread.joinable()) {
        mPendingWritesThread.join();
    }
    if (mWakelockThread.joinable()) {
        mWakelockThread.join();
    }
}

void HalProxy::disableAllSensors() {
    for (const auto& sensorEntry : mSensors) {
        int32_t sensorHandle = sensorEntry.first;
        activate(sensorHandle, false /* enabled */);
    }
    std::lock_guard<std::mutex> dynamicSensorsLock(mDynamicSensorsMutex);
    for (const auto& sensorEntry : mDynamicSensors) {
        int32_t sensorHandle = sensorEntry.first;
        activate(sensorHandle, false /* enabled */);
    }
}

void HalProxy::startPendingWritesThread(HalProxy* halProxy) {
    halProxy->handlePendingWrites();
}
@@ -347,8 +394,6 @@ void HalProxy::handlePendingWrites() {
            size_t eventQueueSize = mEventQueue->getQuantumCount();
            size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize);
            lock.unlock();
            // TODO: Find a way to interrup writeBlocking if the thread should exit
            // so we don't have to wait for timeout on framework restarts.
            if (!mEventQueue->writeBlocking(
                        pendingWriteEvents.data(), numToWrite,
                        static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+16 −2
Original line number Diff line number Diff line
@@ -149,9 +149,13 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter {
    std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;

    /**
     * Event Flag to signal to the framework when sensor events are available to be read
     * Event Flag to signal to the framework when sensor events are available to be read and to
     * interrupt event queue blocking write.
     */
    EventFlag* mEventQueueFlag;
    EventFlag* mEventQueueFlag = nullptr;

    //! Event Flag to signal internally that the wakelock queue should stop its blocking read.
    EventFlag* mWakelockQueueFlag = nullptr;

    /**
     * Callback to the sensors framework to inform it that new sensors have been added or removed.
@@ -253,6 +257,16 @@ class HalProxy : public ISensors, public IScopedWakelockRefCounter {
     */
    void init();

    /**
     * Stops all threads by setting the threads running flag to false and joining to them.
     */
    void stopThreads();

    /**
     * Disable all the sensors observed by the HalProxy.
     */
    void disableAllSensors();

    /**
     * Starts the thread that handles pending writes to event fmq.
     *
+7 −5
Original line number Diff line number Diff line
@@ -130,11 +130,13 @@ class ISensorsSubHal : public ISensors {
    virtual const std::string getName() = 0;

    /**
     * First method invoked on the sub-HAL after it's allocated through sensorsHalGetSubHal() by the
     * HalProxy. Sub-HALs should use this to initialize any state and retain the callback given in
     * order to communicate with the HalProxy. Method will be called anytime the sensors framework
     * restarts. Therefore, this method will be responsible for reseting the state of the subhal and
     * cleaning up and reallocating any previously allocated data.
     * This is the first method invoked on the sub-HAL after it's allocated through
     * sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and
     * retain the callback given in order to communicate with the HalProxy. Method will be called
     * anytime the sensors framework restarts. Therefore, this method will be responsible for
     * reseting the state of the subhal and cleaning up and reallocating any previously allocated
     * data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state
     * as well.
     *
     * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state
     *     changes, new sensor events should be sent to the framework, and when a new ScopedWakelock
+138 −6
Original line number Diff line number Diff line
@@ -432,7 +432,7 @@ TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) {
    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
}

TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThreadTest) {
TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) {
    constexpr size_t kQueueSize = 5;
    constexpr size_t kNumEvents = 6;
    AllSensorsSubHal subHal;
@@ -447,13 +447,145 @@ TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThreadTest) {
    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
    subHal.postEvents(events, false /* wakeup */);

    // Sleep for a half second so that background thread has time to attempt it's blocking write
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    // Destructing HalProxy object with events on the background thread
}

TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) {
    constexpr size_t kQueueSize = 5;
    AllSensorsSubHal subHal;
    std::vector<ISensorsSubHal*> subHals{&subHal};

    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
    HalProxy proxy(subHals);
    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);

    std::vector<Event> events{makeProximityEvent()};
    subHal.postEvents(events, true /* wakeup */);

    // Not sending any acks back through wakeLockQueue

    // Destructing HalProxy object with unacked wakeup events posted
}

TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) {
    constexpr size_t kQueueSize = 5;
    constexpr size_t kNumEvents = 10;
    AllSensorsSubHal subHal;
    std::vector<ISensorsSubHal*> subHals{&subHal};

    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
    HalProxy proxy(subHals);
    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);

    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
    subHal.postEvents(events, false /* wakeup */);

    eventQueue = makeEventFMQ(kQueueSize);
    wakeLockQueue = makeWakelockFMQ(kQueueSize);

    Result secondInitResult =
            proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
    EXPECT_EQ(secondInitResult, Result::OK);
    // Small sleep so that pending writes thread has a change to hit writeBlocking call.
    std::this_thread::sleep_for(std::chrono::milliseconds(5));
    Event eventOut;
    EXPECT_FALSE(eventQueue->read(&eventOut));
}

TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) {
    constexpr size_t kQueueSize = 5;
    AllSensorsSubHal subHal;
    std::vector<ISensorsSubHal*> subHals{&subHal};

    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
    HalProxy proxy(subHals);
    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);

    std::vector<Event> events{makeProximityEvent()};
    subHal.postEvents(events, true /* wakeup */);

    // Not sending any acks back through wakeLockQueue

    eventQueue = makeEventFMQ(kQueueSize);
    wakeLockQueue = makeWakelockFMQ(kQueueSize);

    Result secondInitResult =
            proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
    EXPECT_EQ(secondInitResult, Result::OK);
}

TEST(HalProxyTest, InitializeManyTimesInARow) {
    constexpr size_t kQueueSize = 5;
    constexpr size_t kNumTimesToInit = 100;
    AllSensorsSubHal subHal;
    std::vector<ISensorsSubHal*> subHals{&subHal};

    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
    HalProxy proxy(subHals);

    for (size_t i = 0; i < kNumTimesToInit; i++) {
        Result secondInitResult =
                proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
        EXPECT_EQ(secondInitResult, Result::OK);
    }
}

TEST(HalProxyTest, OperationModeResetOnInitialize) {
    constexpr size_t kQueueSize = 5;
    AllSensorsSubHal subHal;
    std::vector<ISensorsSubHal*> subHals{&subHal};
    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
    HalProxy proxy(subHals);
    proxy.setOperationMode(OperationMode::DATA_INJECTION);
    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
    Event event = makeAccelerometerEvent();
    // Should not be able to inject a non AdditionInfo type event because operation mode should
    // have been reset to NORMAL
    EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
}

TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) {
    constexpr size_t kQueueSize = 5;
    constexpr size_t kNumSensors = 5;
    AddAndRemoveDynamicSensorsSubHal subHal;
    std::vector<ISensorsSubHal*> subHals{&subHal};
    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
    HalProxy proxy(subHals);

    std::vector<SensorInfo> sensorsToConnect;
    std::vector<int32_t> sensorHandlesToAttemptToRemove;
    makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
                                                 sensorHandlesToAttemptToRemove);

    std::vector<int32_t> nonDynamicSensorHandles;
    for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
        nonDynamicSensorHandles.push_back(sensorHandle);
    }

    TestSensorsCallback* callback = new TestSensorsCallback();
    ::android::sp<ISensorsCallback> callbackPtr = callback;
    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
    subHal.addDynamicSensors(sensorsToConnect);

    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
    subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);

    // Should see a 5 second wait for blocking write timeout here
    std::vector<int32_t> sensorHandlesActuallyRemoved = callback->getSensorHandlesDisconnected();

    // Should be one events left on pending writes queue here and proxy will destruct
    // If this TEST completes then it was a success, if it hangs we will see a crash
    // Should not have received the sensorHandles for any dynamic sensors that were removed since
    // all of them should have been removed in the second initialize call.
    EXPECT_TRUE(sensorHandlesActuallyRemoved.empty());
}

TEST(HalProxyTest, DynamicSensorsConnectedTest) {
+1 −0
Original line number Diff line number Diff line
@@ -158,6 +158,7 @@ Return<void> SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec<hidl_str

Return<Result> SensorsSubHal::initialize(const sp<IHalProxyCallback>& halProxyCallback) {
    mCallback = halProxyCallback;
    setOperationMode(OperationMode::NORMAL);
    return Result::OK;
}