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

Commit 5373303c authored by Tomasz Wasilczyk's avatar Tomasz Wasilczyk Committed by Android (Google) Code Review
Browse files

Merge "Implement Minimal Telephony" into main

parents b66981d2 610ca0e6
Loading
Loading
Loading
Loading
+85 −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.

package {
    // See: http://go/android-license-faq
    // A large-scale-change added 'default_applicable_licenses' to import
    // all of the 'license_kinds' from "hardware_interfaces_license"
    // to get the below license kinds:
    //   SPDX-license-identifier-Apache-2.0
    default_applicable_licenses: ["hardware_interfaces_license"],
}

cc_defaults {
    name: "android.hardware.radio-minradio@defaults",
    relative_install_path: "hw",
    vendor: true,
    cflags: [
        "-Wall",
        "-Wextra",
        "-Werror",
        "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
        "-g",

        // binder_to_string.h uses deprecated codecvt_utf8_utf16.
        // We can't fix it in foreesable future.
        "-D_LIBCPP_DISABLE_DEPRECATION_WARNINGS",
    ],
    shared_libs: [
        "android.hardware.radio.config-V4-ndk",
        "android.hardware.radio.data-V4-ndk",
        "android.hardware.radio.modem-V4-ndk",
        "android.hardware.radio.network-V4-ndk",
        "android.hardware.radio.sim-V4-ndk",
        "libbase",
        "libbinder_ndk",
        "libutils",
    ],
    sanitize: {
        address: true,
        all_undefined: true,
        fuzzer: true,
        integer_overflow: true,
    },
    strip: {
        none: true,
    },
}

cc_library {
    name: "android.hardware.radio-library.minradio",
    defaults: ["android.hardware.radio-minradio@defaults"],
    export_include_dirs: ["include"],
    srcs: [
        "RadioSlotBase.cpp",
        "ResponseTracker.cpp",
        "SlotContext.cpp",
        "config/RadioConfig.cpp",
        "data/RadioData.cpp",
        "modem/RadioModem.cpp",
        "modem/RadioModemResponseTracker.cpp",
        "network/RadioNetwork.cpp",
        "network/RadioNetworkResponseTracker.cpp",
        "network/structs.cpp",
        "response.cpp",
        "sim/apps/AraM.cpp",
        "sim/apps/FilesystemApp.cpp",
        "sim/apps/tlv.cpp",
        "sim/App.cpp",
        "sim/AppManager.cpp",
        "sim/Filesystem.cpp",
        "sim/IccUtils.cpp",
        "sim/RadioSim.cpp",
    ],
}
+23 −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 <libminradio/RadioSlotBase.h>

namespace android::hardware::radio::minimal {

RadioSlotBase::RadioSlotBase(std::shared_ptr<SlotContext> context) : mContext(context) {}

}  // namespace android::hardware::radio::minimal
+165 −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 <libminradio/ResponseTracker.h>

#include <libminradio/debug.h>

#include <random>

namespace android::hardware::radio::minimal {

using namespace ::android::hardware::radio::minimal::binder_printing;
using ::aidl::android::hardware::radio::RadioError;
using ::aidl::android::hardware::radio::RadioResponseInfo;
using ::ndk::ScopedAStatus;

RadioError ResponseTrackerResultBase::toError(const ScopedAStatus& status) {
    CHECK(!status.isOk()) << "statusToError called with no error";
    return RadioError::GENERIC_FAILURE;
}

ResponseTrackerResultBase::ResponseTrackerResultBase(const char* descriptor)
    : ResponseTrackerResultBase(descriptor, RadioError::RADIO_NOT_AVAILABLE) {}

ResponseTrackerResultBase::ResponseTrackerResultBase(const char* descriptor, RadioError error)
    : mDescriptor(descriptor), mError(error) {}

ResponseTrackerResultBase::ResponseTrackerResultBase(const char* descriptor, ScopedAStatus st)
    : ResponseTrackerResultBase(descriptor, toError(st)) {}

bool ResponseTrackerResultBase::isOk() const {
    return mError == RadioError::NONE;
}

bool ResponseTrackerResultBase::expectOk() const {
    if (isOk()) return true;
    LOG(ERROR) << "Request for " << mDescriptor << " failed: " << mError;
    return false;
}

RadioError ResponseTrackerResultBase::getError() const {
    return mError;
}

const char* ResponseTrackerResultBase::getDescriptor() const {
    return mDescriptor;
}

ResponseTrackerBase::ScopedSerial::ScopedSerial(int32_t serial, ResponseTrackerBase* tracker)
    : mSerial(serial), mTracker(tracker) {}

ResponseTrackerBase::ScopedSerial::~ScopedSerial() {
    if (mIsReleased) return;
    mTracker->cancelTracking(*this);
}

ResponseTrackerBase::ScopedSerial::operator int32_t() const {
    CHECK(!mIsReleased) << "ScopedSerial " << mSerial << " is not valid anymore";
    return mSerial;
}

void ResponseTrackerBase::ScopedSerial::release() {
    mIsReleased = true;
}

int32_t ResponseTrackerBase::initialSerial() {
    /* Android framework tends to start request serial numbers from 0, so let's pick something from
     * the second quarter of int32_t negative range. This way the chance of having a conflict is
     * closer to zero. */
    static const int32_t rangeSize = std::abs(std::numeric_limits<int32_t>::min() / 4);
    static const int32_t rangeStart = std::numeric_limits<int32_t>::min() + rangeSize;

    static std::random_device generator;
    static std::uniform_int_distribution<int32_t> distribution(rangeStart, rangeStart + rangeSize);

    return distribution(generator);
}

ResponseTrackerBase::ScopedSerial ResponseTrackerBase::newSerial() {
    std::unique_lock lck(mSerialsGuard);

    auto serial = mSerial++;
    if (serial == 0) [[unlikely]] {
        serial = mSerial++;
    }
    if constexpr (debug::kSuperCrazyVerbose) {
        LOG(VERBOSE) << "Tracking " << serial << " internally";
    }

    auto inserted = mTrackedSerials.emplace(serial, nullptr).second;
    CHECK(inserted) << "Detected tracked serials conflict at " << serial;

    return {serial, this};
}

bool ResponseTrackerBase::isTracked(int32_t serial) const {
    std::unique_lock lck(mSerialsGuard);
    return mTrackedSerials.contains(serial);
}

void ResponseTrackerBase::cancelTracking(ResponseTrackerBase::ScopedSerial& serial) {
    std::unique_lock lck(mSerialsGuard);
    auto erased = mTrackedSerials.erase(serial);
    CHECK(erased == 1) << "Couldn't cancel tracking " << serial;
    LOG(VERBOSE) << "Cancelled tracking " << serial << " internally";
    serial.release();
}

ScopedAStatus ResponseTrackerBase::handle(const RadioResponseInfo& info,
                                          std::unique_ptr<ResponseTrackerResultBase> result) {
    std::unique_lock lck(mSerialsGuard);
    if constexpr (debug::kSuperCrazyVerbose) {
        LOG(VERBOSE) << "Handling " << info.serial << " internally (not sending to the framework)";
    }

    auto it = mTrackedSerials.find(info.serial);
    CHECK(it != mTrackedSerials.end()) << "Request not tracked: " << info;
    CHECK(it->second == nullptr) << "Request already handled: " << info;
    it->second = std::move(result);

    return ScopedAStatus::ok();
}

std::unique_ptr<ResponseTrackerResultBase> ResponseTrackerBase::getResultBase(
        ResponseTrackerBase::ScopedSerial& serial) {
    std::unique_lock lck(mSerialsGuard);
    auto node = mTrackedSerials.extract(serial);
    CHECK(node.key()) << "Request " << serial << " is not tracked";
    if (!node.mapped()) {
        LOG(WARNING) << "Didn't get result for " << serial
                     << ". It may either mean setResponseFunctions has reset the callbacks or"
                        " the callback wasn't called synchronously from the scope of "
                        "request method implementation.";
        serial.release();
        return nullptr;
    }
    if constexpr (debug::kSuperCrazyVerbose) {
        LOG(VERBOSE) << "Finished tracking " << serial << " internally";
    }
    serial.release();
    return std::move(node.mapped());
}

// This symbol silences "Mismatched versions of delegator and implementation" errors from Delegator
// implementation. In this specific case, Delegators are used to encapsulate incoming callbacks, not
// outgoing interfaces - so clamping delegator interface version to lower than implementation's
// version wouldn't make any difference - the local binary wouldn't know what to do with a newer
// interface anyways. This happens when Radio HAL (which includes callback interfaces) defined on
// system partition is newer than one used to build local binary (usually on vendor partition).
extern "C" void assert2_no_op(const char*, int, const char*, const char*) {}

}  // namespace android::hardware::radio::minimal
+27 −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 <libminradio/SlotContext.h>

namespace android::hardware::radio::minimal {

SlotContext::SlotContext(unsigned slotIndex) : mSlotIndex(slotIndex) {}

unsigned SlotContext::getSlotIndex() const {
    return mSlotIndex;
}

}  // namespace android::hardware::radio::minimal
+119 −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 <libminradio/config/RadioConfig.h>

#include <libminradio/debug.h>
#include <libminradio/response.h>

#define RADIO_MODULE "Config"

namespace android::hardware::radio::minimal {

using namespace ::android::hardware::radio::minimal::binder_printing;
using ::aidl::android::hardware::radio::RadioError;
using ::ndk::ScopedAStatus;
namespace aidl = ::aidl::android::hardware::radio::config;
constexpr auto ok = &ScopedAStatus::ok;

RadioConfig::RadioConfig() {}

ScopedAStatus RadioConfig::getHalDeviceCapabilities(int32_t serial) {
    LOG_CALL;
    /* modemReducedFeatureSet1 disables:
     *  - android.hardware.radio.network.LinkCapacityEstimate.secondaryDownlinkCapacityKbps
     *  - android.hardware.radio.network.LinkCapacityEstimate.secondaryUplinkCapacityKbps
     *  - android.hardware.radio.network.IRadioNetwork.setNrDualConnectivityState
     *  - android.hardware.radio.network.IRadioNetwork.isNrDualConnectivityEnabled
     *  - android.hardware.radio.data.IRadioData.setDataThrottling
     *  - android.hardware.radio.data.IRadioData.getSlicingConfig
     *  - android.hardware.radio.network.IRadioNetworkIndication.currentPhysicalChannelConfigs
     */
    respond()->getHalDeviceCapabilitiesResponse(noError(serial), /*modemReducedFeatureSet1*/ true);
    return ok();
}

ScopedAStatus RadioConfig::getNumOfLiveModems(int32_t serial) {
    LOG_CALL;
    respond()->getNumOfLiveModemsResponse(noError(serial), 1);
    return ok();
}

ScopedAStatus RadioConfig::getPhoneCapability(int32_t serial) {
    LOG_CALL;
    aidl::PhoneCapability cap{
            .maxActiveData = 1,
            .maxActiveInternetData = 1,
            .isInternetLingeringSupported = false,
            .logicalModemIds = {0},
    };
    respond()->getPhoneCapabilityResponse(noError(serial), cap);
    return ok();
}

ScopedAStatus RadioConfig::setNumOfLiveModems(int32_t serial, int8_t numOfLiveModems) {
    LOG_CALL << numOfLiveModems;
    if (numOfLiveModems == 1) {
        respond()->setNumOfLiveModemsResponse(noError(serial));
    } else {
        respond()->setNumOfLiveModemsResponse(errorResponse(serial, RadioError::INVALID_ARGUMENTS));
    }
    return ok();
}

ScopedAStatus RadioConfig::setPreferredDataModem(int32_t serial, int8_t modemId) {
    LOG_CALL_IGNORED << modemId;
    respond()->setPreferredDataModemResponse(
            (modemId == 0) ? noError(serial)
                           : errorResponse(serial, RadioError::INVALID_ARGUMENTS));
    return ok();
}

ScopedAStatus RadioConfig::setResponseFunctions(
        const std::shared_ptr<aidl::IRadioConfigResponse>& response,
        const std::shared_ptr<aidl::IRadioConfigIndication>& indication) {
    LOG_CALL_NOSERIAL << response << ' ' << indication;
    CHECK(response);
    CHECK(indication);
    respond = response;
    indicate = indication;
    return ok();
}

ScopedAStatus RadioConfig::setSimSlotsMapping(  //
        int32_t serial, const std::vector<aidl::SlotPortMapping>& slotMap) {
    LOG_CALL_IGNORED << slotMap;
    respond()->setSimSlotsMappingResponse(noError(serial));
    return ok();
}

ScopedAStatus RadioConfig::getSimultaneousCallingSupport(int32_t serial) {
    LOG_CALL;
    respond()->getSimultaneousCallingSupportResponse(noError(serial), {});
    return ok();
}

ScopedAStatus RadioConfig::getSimTypeInfo(int32_t serial) {
    LOG_NOT_SUPPORTED;
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

ScopedAStatus RadioConfig::setSimType(int32_t serial, const std::vector<aidl::SimType>& simTypes) {
    LOG_NOT_SUPPORTED << simTypes;
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}

}  // namespace android::hardware::radio::minimal
Loading