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

Commit 05e3e6ba authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 11336776 from 278da2e0 to 24Q2-release

Change-Id: I03e9079536e421debd655bea21370d1cdcedfa41
parents 0f5124d4 278da2e0
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -14,10 +14,13 @@
 * limitations under the License.
 */

#include "MockBroadcastRadioCallback.h"

#include <BroadcastRadio.h>
#include <VirtualRadio.h>
#include <broadcastradio-utils-aidl/Utils.h>

#include <android-base/logging.h>
#include <gtest/gtest.h>

namespace aidl::android::hardware::broadcastradio {
@@ -74,10 +77,19 @@ const VirtualRadio& getAmFmMockTestRadio() {
class DefaultBroadcastRadioHalTest : public testing::Test {
  public:
    void SetUp() override {
        ::android::base::SetDefaultTag("BcRadioAidlDef.test");
        const VirtualRadio& amFmRadioMockTest = getAmFmMockTestRadio();
        mBroadcastRadioHal = ::ndk::SharedRefBase::make<BroadcastRadio>(amFmRadioMockTest);
        mTunerCallback = ndk::SharedRefBase::make<MockBroadcastRadioCallback>();
    }

    void TearDown() override {
        mBroadcastRadioHal->unsetTunerCallback();
        EXPECT_FALSE(mTunerCallback->isTunerFailed());
    }

    std::shared_ptr<BroadcastRadio> mBroadcastRadioHal;
    std::shared_ptr<MockBroadcastRadioCallback> mTunerCallback;
};

TEST_F(DefaultBroadcastRadioHalTest, GetAmFmRegionConfig) {
@@ -136,4 +148,24 @@ TEST_F(DefaultBroadcastRadioHalTest, GetProperties) {
    }
}

TEST_F(DefaultBroadcastRadioHalTest, SetTunerCallback) {
    auto halResult = mBroadcastRadioHal->setTunerCallback(mTunerCallback);

    ASSERT_TRUE(halResult.isOk());
}

TEST_F(DefaultBroadcastRadioHalTest, SetTunerCallbackWithNull) {
    auto halResult = mBroadcastRadioHal->setTunerCallback(nullptr);

    ASSERT_EQ(halResult.getServiceSpecificError(), utils::resultToInt(Result::INVALID_ARGUMENTS));
}

TEST_F(DefaultBroadcastRadioHalTest, UnsetTunerCallbackWithNull) {
    ASSERT_TRUE(mBroadcastRadioHal->setTunerCallback(mTunerCallback).isOk());

    auto halResult = mBroadcastRadioHal->unsetTunerCallback();

    ASSERT_TRUE(halResult.isOk());
}

}  // namespace aidl::android::hardware::broadcastradio
+93 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 "MockBroadcastRadioCallback.h"

#include <android-base/logging.h>

namespace aidl::android::hardware::broadcastradio {

namespace {
using std::vector;
}

MockBroadcastRadioCallback::MockBroadcastRadioCallback() {
    mAntennaConnectionState = true;
}

ScopedAStatus MockBroadcastRadioCallback::onTuneFailed(Result result,
                                                       const ProgramSelector& selector) {
    LOG(DEBUG) << "onTuneFailed with result with " << selector.toString().c_str();
    if (result != Result::CANCELED) {
        std::lock_guard<std::mutex> lk(mLock);
        tunerFailed = true;
    }
    return ndk::ScopedAStatus::ok();
}

ScopedAStatus MockBroadcastRadioCallback::onCurrentProgramInfoChanged(const ProgramInfo& info) {
    LOG(DEBUG) << "onCurrentProgramInfoChanged with " << info.toString().c_str();
    {
        std::lock_guard<std::mutex> lk(mLock);
        mCurrentProgramInfo = info;
    }

    mOnCurrentProgramInfoChangedFlag.notify();
    return ndk::ScopedAStatus::ok();
}

ScopedAStatus MockBroadcastRadioCallback::onProgramListUpdated(
        [[maybe_unused]] const ProgramListChunk& chunk) {
    return ndk::ScopedAStatus::ok();
}

ScopedAStatus MockBroadcastRadioCallback::onParametersUpdated(
        [[maybe_unused]] const vector<VendorKeyValue>& parameters) {
    return ndk::ScopedAStatus::ok();
}

ScopedAStatus MockBroadcastRadioCallback::onAntennaStateChange(bool connected) {
    if (!connected) {
        std::lock_guard<std::mutex> lk(mLock);
        mAntennaConnectionState = false;
    }
    return ndk::ScopedAStatus::ok();
}

ScopedAStatus MockBroadcastRadioCallback::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag,
                                                              [[maybe_unused]] bool in_value) {
    return ndk::ScopedAStatus::ok();
}

bool MockBroadcastRadioCallback::waitOnCurrentProgramInfoChangedCallback() {
    return mOnCurrentProgramInfoChangedFlag.wait();
}

void MockBroadcastRadioCallback::reset() {
    mOnCurrentProgramInfoChangedFlag.reset();
}

bool MockBroadcastRadioCallback::isTunerFailed() {
    std::lock_guard<std::mutex> lk(mLock);
    return tunerFailed;
}

ProgramInfo MockBroadcastRadioCallback::getCurrentProgramInfo() {
    std::lock_guard<std::mutex> lk(mLock);
    return mCurrentProgramInfo;
}

}  // namespace aidl::android::hardware::broadcastradio
+103 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.
 */

#pragma once

#include <aidl/android/hardware/broadcastradio/BnTunerCallback.h>
#include <aidl/android/hardware/broadcastradio/ConfigFlag.h>
#include <aidl/android/hardware/broadcastradio/IBroadcastRadio.h>
#include <aidl/android/hardware/broadcastradio/ProgramInfo.h>
#include <aidl/android/hardware/broadcastradio/ProgramListChunk.h>
#include <aidl/android/hardware/broadcastradio/ProgramSelector.h>
#include <aidl/android/hardware/broadcastradio/Result.h>
#include <aidl/android/hardware/broadcastradio/VendorKeyValue.h>

#include <android-base/thread_annotations.h>

#include <broadcastradio-utils-aidl/Utils.h>

#include <condition_variable>

namespace aidl::android::hardware::broadcastradio {

namespace {
using ::ndk::ScopedAStatus;

}  // namespace

class MockBroadcastRadioCallback final : public BnTunerCallback {
  public:
    explicit MockBroadcastRadioCallback();
    ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
    ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
    ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
    ScopedAStatus onParametersUpdated(const std::vector<VendorKeyValue>& parameters) override;
    ScopedAStatus onAntennaStateChange(bool connected) override;
    ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override;

    bool waitOnCurrentProgramInfoChangedCallback();
    bool isTunerFailed();
    void reset();

    ProgramInfo getCurrentProgramInfo();

  private:
    class CallbackFlag final {
      public:
        CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; }
        /**
         * Notify that the callback is called.
         */
        void notify() {
            std::unique_lock<std::mutex> lock(mMutex);
            mCalled = true;
            lock.unlock();
            mCv.notify_all();
        };

        /**
         * Wait for the timeout passed into the constructor.
         */
        bool wait() {
            std::unique_lock<std::mutex> lock(mMutex);
            return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs),
                                [this] { return mCalled; });
        };

        /**
         * Reset the callback to not called.
         */
        void reset() {
            std::unique_lock<std::mutex> lock(mMutex);
            mCalled = false;
        }

      private:
        std::mutex mMutex;
        bool mCalled GUARDED_BY(mMutex) = false;
        std::condition_variable mCv;
        int mTimeoutMs;
    };

    std::mutex mLock;
    bool mAntennaConnectionState GUARDED_BY(mLock);
    bool tunerFailed GUARDED_BY(mLock) = false;
    ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock);
    utils::ProgramInfoSet mProgramList GUARDED_BY(mLock);
    CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS);
};

}  // namespace aidl::android::hardware::broadcastradio
+64 −0
Original line number Diff line number Diff line
@@ -355,6 +355,70 @@ TEST(BroadcastRadioUtilsTest, GetDabSCIdS) {
    ASSERT_EQ(utils::getDabSCIdS(sel), kDabSCIdS);
}

TEST(BroadcastRadioUtilsTest, TunesToWithTheSameHdSelector) {
    ProgramSelector sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
    ProgramSelector selTarget = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);

    ASSERT_TRUE(utils::tunesTo(sel, selTarget));
}

TEST(BroadcastRadioUtilsTest, TunesToAmFmSelectorWithDifferentSubChannels) {
    ProgramSelector sel = utils::makeSelectorHd(kHdStationId, kHdSubChannel, kHdFrequency);
    ProgramSelector selTarget = utils::makeSelectorAmfm(kHdFrequency);

    ASSERT_FALSE(utils::tunesTo(sel, selTarget));
}

TEST(BroadcastRadioUtilsTest, TunesToMainHdChannelWithDifferentSubChannels) {
    ProgramSelector sel = utils::makeSelectorAmfm(kHdFrequency);
    ProgramSelector selTarget =
            utils::makeSelectorHd(kHdStationId, /* subChannel= */ 0, kHdFrequency);

    ASSERT_TRUE(utils::tunesTo(sel, selTarget));
}

TEST(BroadcastRadioUtilsTest, TunesToWithTheSameAmFmSelector) {
    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
    ProgramSelector selTarget = utils::makeSelectorAmfm(kFmFrequencyKHz);

    ASSERT_TRUE(utils::tunesTo(sel, selTarget));
}

TEST(BroadcastRadioUtilsTest, TunesToWithDifferentFrequencies) {
    ProgramSelector sel = utils::makeSelectorAmfm(kFmFrequencyKHz);
    ProgramSelector selTarget = utils::makeSelectorAmfm(kFmFrequencyKHz + 200);

    ASSERT_FALSE(utils::tunesTo(sel, selTarget));
}

TEST(BroadcastRadioUtilsTest, TunesToWithTheSameDabSelector) {
    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
    ProgramSelector selTarget = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);

    ASSERT_TRUE(utils::tunesTo(sel, selTarget));
}

TEST(BroadcastRadioUtilsTest, TunesToWithDabSelectorOfDifferentPrimaryIds) {
    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt + 1, kDabEnsemble, kDabFrequencyKhz);
    ProgramSelector selTarget = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);

    ASSERT_FALSE(utils::tunesTo(sel, selTarget));
}

TEST(BroadcastRadioUtilsTest, TunesToWithDabSelectorOfDifferentSecondayIds) {
    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble + 100, kDabFrequencyKhz);
    ProgramSelector selTarget = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);

    ASSERT_FALSE(utils::tunesTo(sel, selTarget));
}

TEST(BroadcastRadioUtilsTest, TunesToWithDabSelectorWithoutSecondaryIds) {
    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt);
    ProgramSelector selTarget = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);

    ASSERT_TRUE(utils::tunesTo(sel, selTarget));
}

TEST(BroadcastRadioUtilsTest, SatisfiesWithSatisfiedIdTypesFilter) {
    ProgramFilter filter = ProgramFilter{.identifierTypes = {IdentifierType::DAB_FREQUENCY_KHZ}};
    ProgramSelector sel = utils::makeSelectorDab(kDabSidExt, kDabEnsemble, kDabFrequencyKhz);
+28 −15
Original line number Diff line number Diff line
@@ -789,8 +789,10 @@ Status ExternalCameraDeviceSession::switchToOffline(
                outputBuffer.bufferId = buffer.bufferId;
                outputBuffer.status = BufferStatus::ERROR;
                if (buffer.acquireFence >= 0) {
                    outputBuffer.releaseFence.fds.resize(1);
                    outputBuffer.releaseFence.fds.at(0).set(buffer.acquireFence);
                    native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
                    handle->data[0] = buffer.acquireFence;
                    outputBuffer.releaseFence = android::dupToAidl(handle);
                    native_handle_delete(handle);
                }
            } else {
                offlineBuffers.push_back(buffer);
@@ -1389,12 +1391,14 @@ Status ExternalCameraDeviceSession::importRequestLockedImpl(

    // All buffers are imported. Now validate output buffer acquire fences
    for (size_t i = 0; i < numOutputBufs; i++) {
        if (!sHandleImporter.importFence(
                    ::android::makeFromAidl(request.outputBuffers[i].acquireFence), allFences[i])) {
        native_handle_t* h = ::android::makeFromAidl(request.outputBuffers[i].acquireFence);
        if (!sHandleImporter.importFence(h, allFences[i])) {
            ALOGE("%s: output buffer %zu acquire fence is invalid", __FUNCTION__, i);
            cleanupInflightFences(allFences, i);
            native_handle_delete(h);
            return Status::INTERNAL_ERROR;
        }
        native_handle_delete(h);
    }
    return Status::OK;
}
@@ -1768,8 +1772,10 @@ Status ExternalCameraDeviceSession::processCaptureRequestError(
        result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
        result.outputBuffers[i].status = BufferStatus::ERROR;
        if (req->buffers[i].acquireFence >= 0) {
            result.outputBuffers[i].releaseFence.fds.resize(1);
            result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
            native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
            handle->data[0] = req->buffers[i].acquireFence;
            result.outputBuffers[i].releaseFence = android::dupToAidl(handle);
            native_handle_delete(handle);
        }
    }

@@ -1813,16 +1819,20 @@ Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequ
        if (req->buffers[i].fenceTimeout) {
            result.outputBuffers[i].status = BufferStatus::ERROR;
            if (req->buffers[i].acquireFence >= 0) {
                result.outputBuffers[i].releaseFence.fds.resize(1);
                result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
                native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
                handle->data[0] = req->buffers[i].acquireFence;
                result.outputBuffers[i].releaseFence = android::dupToAidl(handle);
                native_handle_delete(handle);
            }
            notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
        } else {
            result.outputBuffers[i].status = BufferStatus::OK;
            // TODO: refactor
            if (req->buffers[i].acquireFence >= 0) {
                result.outputBuffers[i].releaseFence.fds.resize(1);
                result.outputBuffers[i].releaseFence.fds.at(0).set(req->buffers[i].acquireFence);
                native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
                handle->data[0] = req->buffers[i].acquireFence;
                result.outputBuffers[i].releaseFence = android::dupToAidl(handle);
                native_handle_delete(handle);
            }
        }
    }
@@ -2086,9 +2096,10 @@ bool ExternalCameraDeviceSession::BufferRequestThread::threadLoop() {
                    // TODO: create a batch import API so we don't need to lock/unlock mCbsLock
                    // repeatedly?
                    lk.unlock();
                    Status s =
                            parent->importBuffer(streamId, hBuf.bufferId, makeFromAidl(hBuf.buffer),
                    native_handle_t* h = makeFromAidl(hBuf.buffer);
                    Status s = parent->importBuffer(streamId, hBuf.bufferId, h,
                                                    /*out*/ &mBufferReqs[i].bufPtr);
                    native_handle_delete(h);
                    lk.lock();

                    if (s != Status::OK) {
@@ -2096,12 +2107,14 @@ bool ExternalCameraDeviceSession::BufferRequestThread::threadLoop() {
                        cleanupInflightFences(importedFences, i - 1);
                        return false;
                    }
                    if (!sHandleImporter.importFence(makeFromAidl(hBuf.acquireFence),
                                                     mBufferReqs[i].acquireFence)) {
                    h = makeFromAidl(hBuf.acquireFence);
                    if (!sHandleImporter.importFence(h, mBufferReqs[i].acquireFence)) {
                        ALOGE("%s: stream %d import fence failed!", __FUNCTION__, streamId);
                        cleanupInflightFences(importedFences, i - 1);
                        native_handle_delete(h);
                        return false;
                    }
                    native_handle_delete(h);
                    importedFences[i] = mBufferReqs[i].acquireFence;
                } break;
                default:
Loading