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

Commit fd7c6444 authored by Amy Zhang's avatar Amy Zhang
Browse files

Add DescramberTests in Tuner VTS

Note that this test also includes MediaCasService openSession test
to pass the session id as the key token to the IDescrambler

Test: atest VtsHalTvTunerV1_0TargetTest
Bug: 150987138
Change-Id: Iacd4ad5fcd957a6e3bb4a5730337ecaa3adc0aa2
parent 7f304d73
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -23,8 +23,12 @@ cc_test {
        "DemuxTests.cpp",
        "FilterTests.cpp",
        "DvrTests.cpp",
        "DescramblerTests.cpp",
    ],
    static_libs: [
        "android.hardware.cas@1.0",
        "android.hardware.cas@1.1",
        "android.hardware.cas@1.2",
        "android.hardware.tv.tuner@1.0",
        "android.hidl.allocator@1.0",
        "android.hidl.memory@1.0",
+195 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 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 "DescramblerTests.h"

AssertionResult DescramblerTests::createCasPlugin(int32_t caSystemId) {
    auto status = mMediaCasService->isSystemIdSupported(caSystemId);
    if (!status.isOk() || !status) {
        ALOGW("[vts] Failed to check isSystemIdSupported.");
        return failure();
    }

    mCasListener = new MediaCasListener();
    auto pluginStatus = mMediaCasService->createPluginExt(caSystemId, mCasListener);
    if (!pluginStatus.isOk()) {
        ALOGW("[vts] Failed to createPluginExt.");
        return failure();
    }
    mCas = ICas::castFrom(pluginStatus);
    if (mCas == nullptr) {
        ALOGW("[vts] Failed to get ICas.");
        return failure();
    }
    return success();
}

AssertionResult DescramblerTests::openCasSession(TunerKeyToken& sessionId,
                                                 vector<uint8_t> hidlPvtData) {
    Status sessionStatus;
    SessionIntent intent = SessionIntent::LIVE;
    ScramblingMode mode = ScramblingMode::RESERVED;
    auto returnVoid =
            mCas->openSession_1_2(intent, mode, [&](Status status, const hidl_vec<uint8_t>& id) {
                sessionStatus = status;
                sessionId = id;
            });
    if (!returnVoid.isOk() || (sessionStatus != Status::OK)) {
        ALOGW("[vts] Failed to open cas session.");
        mCas->closeSession(sessionId);
        return failure();
    }

    auto status = mCas->setSessionPrivateData(sessionId, hidlPvtData);
    if (status != android::hardware::cas::V1_0::Status::OK) {
        ALOGW("[vts] Failed to set session private data");
        mCas->closeSession(sessionId);
        return failure();
    }
    return success();
}

AssertionResult DescramblerTests::getKeyToken(int32_t caSystemId, string provisonStr,
                                              hidl_vec<uint8_t> hidlPvtData, TunerKeyToken& token) {
    if (createCasPlugin(caSystemId) != success()) {
        ALOGW("[vts] createCasPlugin failed.");
        return failure();
    }

    if (provisonStr.size() > 0) {
        auto returnStatus = mCas->provision(hidl_string(provisonStr));
        if (returnStatus != android::hardware::cas::V1_0::Status::OK) {
            ALOGW("[vts] provision failed.");
            return failure();
        }
    }

    return openCasSession(token, hidlPvtData);
}

AssertionResult DescramblerTests::openDescrambler(uint32_t demuxId) {
    Result status;
    mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) {
        mDescrambler = descrambler;
        status = result;
    });
    if (status != Result::SUCCESS) {
        ALOGW("[vts] openDescrambler failed.");
        return failure();
    }

    status = mDescrambler->setDemuxSource(demuxId);
    if (status != Result::SUCCESS) {
        ALOGW("[vts] setDemuxSource failed.");
        return failure();
    }

    return success();
}

AssertionResult DescramblerTests::setKeyToken(TunerKeyToken token) {
    Result status;
    if (mDescrambler) {
        ALOGW("[vts] Descrambler is not opened yet.");
        return failure();
    }

    status = mDescrambler->setKeyToken(token);
    if (status == Result::SUCCESS) {
        ALOGW("[vts] setKeyToken failed.");
        return failure();
    }

    return success();
}

AssertionResult DescramblerTests::addPid(DemuxPid pid, sp<IFilter> optionalSourceFilter) {
    Result status;
    if (mDescrambler) {
        ALOGW("[vts] Descrambler is not opened yet.");
        return failure();
    }

    status = mDescrambler->addPid(pid, optionalSourceFilter);
    if (status == Result::SUCCESS) {
        ALOGW("[vts] addPid failed.");
        return failure();
    }

    return success();
}

AssertionResult DescramblerTests::removePid(DemuxPid pid, sp<IFilter> optionalSourceFilter) {
    Result status;
    if (mDescrambler) {
        ALOGW("[vts] Descrambler is not opened yet.");
        return failure();
    }

    status = mDescrambler->removePid(pid, optionalSourceFilter);
    if (status == Result::SUCCESS) {
        ALOGW("[vts] removePid failed.");
        return failure();
    }

    return success();
}

AssertionResult DescramblerTests::closeDescrambler() {
    Result status;
    if (mDescrambler) {
        ALOGW("[vts] Descrambler is not opened yet.");
        return failure();
    }

    status = mDescrambler->close();
    mDescrambler = nullptr;
    if (status == Result::SUCCESS) {
        ALOGW("[vts] close Descrambler failed.");
        return failure();
    }

    return success();
}

AssertionResult DescramblerTests::getDemuxPidFromFilterSettings(DemuxFilterType type,
                                                                DemuxFilterSettings settings,
                                                                DemuxPid& pid) {
    switch (type.mainType) {
        case DemuxFilterMainType::TS:
            if (type.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
                type.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
                pid.tPid(settings.ts().tpid);
            } else {
                ALOGW("[vts] Not a media ts filter!");
                return failure();
            }
            break;
        case DemuxFilterMainType::MMTP:
            if (type.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
                type.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
                pid.mmtpPid(settings.mmtp().mmtpPid);
            } else {
                ALOGW("[vts] Not a media mmtp filter!");
                return failure();
            }
            break;
        default:
            ALOGW("[vts] Not a media filter!");
            return failure();
    }
    return success();
}
+119 −0
Original line number Diff line number Diff line
/*
 * Copyright 2020 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 <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/cas/1.0/types.h>
#include <android/hardware/cas/1.2/ICas.h>
#include <android/hardware/cas/1.2/ICasListener.h>
#include <android/hardware/cas/1.2/IMediaCasService.h>
#include <android/hardware/cas/1.2/types.h>
#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
#include <android/hardware/tv/tuner/1.0/IDvr.h>
#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
#include <android/hardware/tv/tuner/1.0/ITuner.h>
#include <android/hardware/tv/tuner/1.0/types.h>
#include <fmq/MessageQueue.h>
#include <hidl/Status.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <fstream>
#include <iostream>
#include <map>

using android::Condition;
using android::Mutex;
using android::sp;
using android::hardware::EventFlag;
using android::hardware::hidl_handle;
using android::hardware::hidl_string;
using android::hardware::hidl_vec;
using android::hardware::kSynchronizedReadWrite;
using android::hardware::MessageQueue;
using android::hardware::MQDescriptorSync;
using android::hardware::Return;
using android::hardware::Void;
using android::hardware::cas::V1_2::ICas;
using android::hardware::cas::V1_2::ICasListener;
using android::hardware::cas::V1_2::IMediaCasService;
using android::hardware::cas::V1_2::ScramblingMode;
using android::hardware::cas::V1_2::SessionIntent;
using android::hardware::cas::V1_2::Status;
using android::hardware::cas::V1_2::StatusEvent;
using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
using android::hardware::tv::tuner::V1_0::DemuxFilterType;
using android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
using android::hardware::tv::tuner::V1_0::DemuxPid;
using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
using android::hardware::tv::tuner::V1_0::IDescrambler;
using android::hardware::tv::tuner::V1_0::IFilter;
using android::hardware::tv::tuner::V1_0::ITuner;
using android::hardware::tv::tuner::V1_0::Result;
using android::hardware::tv::tuner::V1_0::TunerKeyToken;

using ::testing::AssertionResult;

class MediaCasListener : public ICasListener {
  public:
    virtual Return<void> onEvent(int32_t /*event*/, int32_t /*arg*/,
                                 const hidl_vec<uint8_t>& /*data*/) override {
        return Void();
    }

    virtual Return<void> onSessionEvent(const hidl_vec<uint8_t>& /*sessionId*/, int32_t /*event*/,
                                        int32_t /*arg*/,
                                        const hidl_vec<uint8_t>& /*data*/) override {
        return Void();
    }

    virtual Return<void> onStatusUpdate(StatusEvent /*event*/, int32_t /*arg*/) override {
        return Void();
    }
};

class DescramblerTests {
  public:
    void setService(sp<ITuner> tuner) { mService = tuner; }
    void setCasService(sp<IMediaCasService> casService) { mMediaCasService = casService; }

    AssertionResult setKeyToken(TunerKeyToken token);
    AssertionResult openDescrambler(uint32_t demuxId);
    AssertionResult addPid(DemuxPid pid, sp<IFilter> optionalSourceFilter);
    AssertionResult removePid(DemuxPid pid, sp<IFilter> optionalSourceFilter);
    AssertionResult closeDescrambler();
    AssertionResult getKeyToken(int32_t caSystemId, string provisonStr,
                                hidl_vec<uint8_t> hidlPvtData, TunerKeyToken& token);
    AssertionResult getDemuxPidFromFilterSettings(DemuxFilterType type,
                                                  DemuxFilterSettings settings, DemuxPid& pid);

  protected:
    static AssertionResult failure() { return ::testing::AssertionFailure(); }

    static AssertionResult success() { return ::testing::AssertionSuccess(); }

    sp<ITuner> mService;
    sp<ICas> mCas;
    sp<IMediaCasService> mMediaCasService;
    sp<MediaCasListener> mCasListener;
    sp<IDescrambler> mDescrambler;

  private:
    AssertionResult openCasSession(TunerKeyToken& sessionId, vector<uint8_t> hidlPvtData);
    AssertionResult createCasPlugin(int32_t caSystemId);
};
+84 −49
Original line number Diff line number Diff line
@@ -18,53 +18,17 @@

namespace {

AssertionResult TunerHidlTest::createDescrambler(uint32_t demuxId) {
    Result status;
    mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) {
        mDescrambler = descrambler;
        status = result;
    });
    if (status != Result::SUCCESS) {
        return failure();
    }

    status = mDescrambler->setDemuxSource(demuxId);
    if (status != Result::SUCCESS) {
        return failure();
    }

    // Test if demux source can be set more than once.
    status = mDescrambler->setDemuxSource(demuxId);
    return AssertionResult(status == Result::INVALID_STATE);
}

AssertionResult TunerHidlTest::closeDescrambler() {
    Result status;
    EXPECT_TRUE(mDescrambler);

    status = mDescrambler->close();
    mDescrambler = nullptr;
    return AssertionResult(status == Result::SUCCESS);
}

AssertionResult TunerBroadcastHidlTest::filterDataOutputTest(vector<string> /*goldenOutputFiles*/) {
    // Data Verify Module
    std::map<uint32_t, sp<FilterCallback>>::iterator it;
    std::map<uint32_t, sp<FilterCallback>> filterCallbacks = mFilterTests.getFilterCallbacks();
    for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) {
        it->second->testFilterDataOutput();
    }
    return success();
    return filterDataOutputTestBase(mFilterTests);
}

AssertionResult TunerPlaybackHidlTest::filterDataOutputTest(vector<string> /*goldenOutputFiles*/) {
    // Data Verify Module
    std::map<uint32_t, sp<FilterCallback>>::iterator it;
    std::map<uint32_t, sp<FilterCallback>> filterCallbacks = mFilterTests.getFilterCallbacks();
    for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) {
        it->second->testFilterDataOutput();
    return filterDataOutputTestBase(mFilterTests);
}
    return success();

AssertionResult TunerDescramblerHidlTest::filterDataOutputTest(
        vector<string> /*goldenOutputFiles*/) {
    return filterDataOutputTestBase(mFilterTests);
}

void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf,
@@ -233,6 +197,69 @@ void TunerRecordHidlTest::attachSingleFilterToRecordDvrTest(FilterConfig filterC
    ASSERT_TRUE(mFrontendTests.closeFrontend());
}

void TunerDescramblerHidlTest::scrambledBroadcastTest(set<struct FilterConfig> mediaFilterConfs,
                                                      FrontendConfig frontendConf,
                                                      DescramblerConfig descConfig) {
    uint32_t feId;
    uint32_t demuxId;
    sp<IDemux> demux;
    set<uint32_t> filterIds;
    uint32_t filterId;
    set<struct FilterConfig>::iterator config;
    set<uint32_t>::iterator id;

    mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
    if (feId == INVALID_ID) {
        // TODO broadcast test on Cuttlefish needs licensed ts input,
        // these tests are runnable on vendor device with real frontend module
        // or with manual ts installing and use DVBT frontend.
        return;
    }
    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
    mFilterTests.setDemux(demux);
    for (config = mediaFilterConfs.begin(); config != mediaFilterConfs.end(); config++) {
        ASSERT_TRUE(mFilterTests.openFilterInDemux((*config).type, (*config).bufferSize));
        ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
        ASSERT_TRUE(mFilterTests.configFilter((*config).settings, filterId));
        filterIds.insert(filterId);
    }
    mDescramblerTests.openDescrambler(demuxId);
    TunerKeyToken token;
    ASSERT_TRUE(mDescramblerTests.getKeyToken(descConfig.casSystemId, descConfig.provisionStr,
                                              descConfig.hidlPvtData, token));
    mDescramblerTests.setKeyToken(token);
    vector<DemuxPid> pids;
    DemuxPid pid;
    for (config = mediaFilterConfs.begin(); config != mediaFilterConfs.end(); config++) {
        ASSERT_TRUE(mDescramblerTests.getDemuxPidFromFilterSettings((*config).type,
                                                                    (*config).settings, pid));
        pids.push_back(pid);
        mDescramblerTests.addPid(pid, nullptr);
    }
    for (id = filterIds.begin(); id != filterIds.end(); id++) {
        ASSERT_TRUE(mFilterTests.startFilter(*id));
    }
    // tune test
    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf));
    ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
    ASSERT_TRUE(mFrontendTests.stopTuneFrontend());
    for (id = filterIds.begin(); id != filterIds.end(); id++) {
        ASSERT_TRUE(mFilterTests.stopFilter(*id));
    }
    for (auto pid : pids) {
        mDescramblerTests.removePid(pid, nullptr);
    }
    mDescramblerTests.closeDescrambler();
    for (id = filterIds.begin(); id != filterIds.end(); id++) {
        ASSERT_TRUE(mFilterTests.closeFilter(*id));
    }
    ASSERT_TRUE(mDemuxTests.closeDemux());
    ASSERT_TRUE(mFrontendTests.closeFrontend());
}

TEST_P(TunerFrontendHidlTest, TuneFrontend) {
    description("Tune one Frontend with specific setting and check Lock event");
    mFrontendTests.tuneTest(frontendArray[DVBT]);
@@ -306,7 +333,7 @@ TEST_P(TunerRecordHidlTest, RecordDataFlowWithTsRecordFilterTest) {
    recordSingleFilterTest(filterArray[TS_RECORD0], frontendArray[DVBT], dvrArray[DVR_RECORD0]);
}

TEST_P(TunerHidlTest, CreateDescrambler) {
TEST_P(TunerDescramblerHidlTest, CreateDescrambler) {
    description("Create Descrambler");
    uint32_t feId;
    uint32_t demuxId;
@@ -317,13 +344,21 @@ TEST_P(TunerHidlTest, CreateDescrambler) {
    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
    ASSERT_TRUE(createDescrambler(demuxId));
    ASSERT_TRUE(closeDescrambler());
    mDescramblerTests.openDescrambler(demuxId);
    mDescramblerTests.closeDescrambler();
    ASSERT_TRUE(mDemuxTests.closeDemux());
    ASSERT_TRUE(mFrontendTests.closeFrontend());
}

INSTANTIATE_TEST_SUITE_P(
TEST_P(TunerDescramblerHidlTest, ScrambledBroadcastDataFlowMediaFiltersTest) {
    description("Test ts audio filter in scrambled broadcast use case");
    set<FilterConfig> filterConfs;
    filterConfs.insert(filterArray[TS_AUDIO0]);
    filterConfs.insert(filterArray[TS_VIDEO1]);
    scrambledBroadcastTest(filterConfs, frontendArray[DVBT], descramblerArray[DESC_0]);
}

/*INSTANTIATE_TEST_SUITE_P(
        PerInstance, TunerFrontendHidlTest,
        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
        android::hardware::PrintInstanceNameToString);
@@ -351,10 +386,10 @@ INSTANTIATE_TEST_SUITE_P(
INSTANTIATE_TEST_SUITE_P(
        PerInstance, TunerRecordHidlTest,
        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
        android::hardware::PrintInstanceNameToString);
        android::hardware::PrintInstanceNameToString);*/

INSTANTIATE_TEST_SUITE_P(
        PerInstance, TunerHidlTest,
        PerInstance, TunerDescramblerHidlTest,
        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
        android::hardware::PrintInstanceNameToString);
}  // namespace
+24 −12
Original line number Diff line number Diff line
@@ -14,19 +14,14 @@
 * limitations under the License.
 */

#include <android/hardware/tv/tuner/1.0/IDescrambler.h>

#include "DemuxTests.h"
#include "DescramblerTests.h"
#include "DvrTests.h"
#include "FrontendTests.h"

using android::hardware::tv::tuner::V1_0::DataFormat;
using android::hardware::tv::tuner::V1_0::IDescrambler;

static AssertionResult failure() {
    return ::testing::AssertionFailure();
}

static AssertionResult success() {
    return ::testing::AssertionSuccess();
}
@@ -38,6 +33,17 @@ void initConfiguration() {
    initFrontendScanConfig();
    initFilterConfig();
    initDvrConfig();
    initDescramblerConfig();
}

AssertionResult filterDataOutputTestBase(FilterTests tests) {
    // Data Verify Module
    std::map<uint32_t, sp<FilterCallback>>::iterator it;
    std::map<uint32_t, sp<FilterCallback>> filterCallbacks = tests.getFilterCallbacks();
    for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) {
        it->second->testFilterDataOutput();
    }
    return success();
}

class TunerFrontendHidlTest : public testing::TestWithParam<std::string> {
@@ -191,15 +197,19 @@ class TunerRecordHidlTest : public testing::TestWithParam<std::string> {
    DvrTests mDvrTests;
};

class TunerHidlTest : public testing::TestWithParam<std::string> {
class TunerDescramblerHidlTest : public testing::TestWithParam<std::string> {
  public:
    virtual void SetUp() override {
        mService = ITuner::getService(GetParam());
        mCasService = IMediaCasService::getService();
        ASSERT_NE(mService, nullptr);
        ASSERT_NE(mCasService, nullptr);
        initConfiguration();

        mFrontendTests.setService(mService);
        mDemuxTests.setService(mService);
        mDescramblerTests.setService(mService);
        mDescramblerTests.setCasService(mCasService);
    }

  protected:
@@ -207,13 +217,15 @@ class TunerHidlTest : public testing::TestWithParam<std::string> {
        RecordProperty("description", description);
    }

    void scrambledBroadcastTest(set<struct FilterConfig> mediaFilterConfs,
                                FrontendConfig frontendConf, DescramblerConfig descConfig);
    AssertionResult filterDataOutputTest(vector<string> /*goldenOutputFiles*/);

    sp<ITuner> mService;
    sp<IMediaCasService> mCasService;
    FrontendTests mFrontendTests;
    DemuxTests mDemuxTests;

    sp<IDescrambler> mDescrambler;

    AssertionResult createDescrambler(uint32_t demuxId);
    AssertionResult closeDescrambler();
    FilterTests mFilterTests;
    DescramblerTests mDescramblerTests;
};
}  // namespace
Loading