Implement Minimal Telephony

Bug: 310710841
Test: atest CtsTelephonyTestCases
Test: atest CtsCarrierApiTestCases
Change-Id: Ia1a5567419871a9c64abb38f2f0e0951cad3fd7b
diff --git a/radio/aidl/minradio/libminradio/modem/RadioModem.cpp b/radio/aidl/minradio/libminradio/modem/RadioModem.cpp
new file mode 100644
index 0000000..1c1c5fa
--- /dev/null
+++ b/radio/aidl/minradio/libminradio/modem/RadioModem.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2023 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/modem/RadioModem.h>
+
+#include <libminradio/debug.h>
+#include <libminradio/response.h>
+
+#define RADIO_MODULE "Modem"
+
+namespace android::hardware::radio::minimal {
+
+using namespace ::android::hardware::radio::minimal::binder_printing;
+using ::aidl::android::hardware::radio::RadioIndicationType;
+using ::ndk::ScopedAStatus;
+namespace aidl = ::aidl::android::hardware::radio::modem;
+namespace aidlRadio = ::aidl::android::hardware::radio;
+constexpr auto ok = &ScopedAStatus::ok;
+
+RadioModem::RadioModem(std::shared_ptr<SlotContext> context,
+                       std::vector<aidlRadio::RadioTechnology> rats)
+    : RadioSlotBase(context) {
+    int32_t ratBitmap = 0;
+    for (auto rat : rats) {
+        CHECK(rat > aidlRadio::RadioTechnology::UNKNOWN) << "Invalid RadioTechnology: " << rat;
+        CHECK(rat <= aidlRadio::RadioTechnology::NR)
+                << ": " << rat << " not supported yet: "
+                << "please verify if RadioAccessFamily for this RadioTechnology is a bit-shifted 1";
+        ratBitmap |= 1 << static_cast<int32_t>(rat);
+    }
+    mRatBitmap = ratBitmap;
+}
+
+std::string RadioModem::getModemUuid() const {
+    // Assumes one modem per slot.
+    return std::format("com.android.minradio.modem{}", mContext->getSlotIndex());
+}
+
+std::string RadioModem::getSimUuid() const {
+    // Assumes one SIM per slot.
+    return std::format("com.android.minradio.sim{}", mContext->getSlotIndex());
+}
+
+ScopedAStatus RadioModem::enableModem(int32_t serial, bool on) {
+    LOG_NOT_SUPPORTED << on;
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ScopedAStatus RadioModem::getBasebandVersion(int32_t serial) {
+    LOG_CALL;
+    respond()->getBasebandVersionResponse(  //
+            noError(serial), std::format("libminradio V{}", IRadioModem::version));
+    return ok();
+}
+
+ScopedAStatus RadioModem::getDeviceIdentity(int32_t serial) {
+    LOG_AND_RETURN_DEPRECATED();
+}
+
+ScopedAStatus RadioModem::getHardwareConfig(int32_t serial) {
+    LOG_CALL;
+
+    aidl::HardwareConfig modem1Config{
+            .type = aidl::HardwareConfig::TYPE_MODEM,
+            .uuid = getModemUuid(),
+            .state = aidl::HardwareConfig::STATE_ENABLED,
+            .modem = {{
+                    .rilModel = 0,  // 0=single (one-to-one relationship for hw and ril daemon)
+                    .rat = static_cast<aidlRadio::RadioTechnology>(mRatBitmap),
+                    .maxVoiceCalls = 0,
+                    .maxDataCalls = 1,
+                    .maxStandby = 1,
+            }},
+    };
+
+    aidl::HardwareConfig sim1Config{
+            .type = aidl::HardwareConfig::TYPE_SIM,
+            .uuid = getSimUuid(),
+            .state = aidl::HardwareConfig::STATE_ENABLED,
+            .sim = {{
+                    .modemUuid = getModemUuid(),
+            }},
+    };
+
+    respond()->getHardwareConfigResponse(noError(serial), {modem1Config, sim1Config});
+    return ok();
+}
+
+ScopedAStatus RadioModem::getModemActivityInfo(int32_t serial) {
+    LOG_CALL_IGNORED;
+    const aidl::ActivityStatsTechSpecificInfo generalActivityStats{
+            .txmModetimeMs = {0, 0, 0, 0, 0},
+    };
+    const aidl::ActivityStatsInfo info{
+            // idleModeTimeMs doesn't make sense for external modem, but the framework
+            // doesn't allow for ModemActivityInfo.isEmpty
+            .idleModeTimeMs = 1,
+            .techSpecificInfo = {generalActivityStats},
+    };
+    respond()->getModemActivityInfoResponse(noError(serial), info);
+    return ok();
+}
+
+ScopedAStatus RadioModem::getModemStackStatus(int32_t serial) {
+    LOG_CALL;
+    respond()->getModemStackStatusResponse(noError(serial), true);
+    return ok();
+}
+
+ScopedAStatus RadioModem::getRadioCapability(int32_t serial) {
+    LOG_CALL;
+    aidl::RadioCapability cap{
+            .session = 0,
+            .phase = aidl::RadioCapability::PHASE_FINISH,
+            .raf = mRatBitmap,  // rafs are nothing else than rat masks
+            .logicalModemUuid = getModemUuid(),
+            .status = aidl::RadioCapability::STATUS_SUCCESS,
+    };
+    respond()->getRadioCapabilityResponse(noError(serial), cap);
+    return ok();
+}
+
+ScopedAStatus RadioModem::nvReadItem(int32_t serial, aidl::NvItem) {
+    LOG_AND_RETURN_DEPRECATED();
+}
+
+ScopedAStatus RadioModem::nvResetConfig(int32_t serial, aidl::ResetNvType resetType) {
+    LOG_CALL << resetType;  // RELOAD is the only non-deprecated argument
+    respond()->nvResetConfigResponse(notSupported(serial));
+    return ok();
+}
+
+ScopedAStatus RadioModem::nvWriteCdmaPrl(int32_t serial, const std::vector<uint8_t>&) {
+    LOG_AND_RETURN_DEPRECATED();
+}
+
+ScopedAStatus RadioModem::nvWriteItem(int32_t serial, const aidl::NvWriteItem&) {
+    LOG_AND_RETURN_DEPRECATED();
+}
+
+ScopedAStatus RadioModem::requestShutdown(int32_t serial) {
+    LOG_NOT_SUPPORTED;
+    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ScopedAStatus RadioModem::responseAcknowledgement() {
+    LOG_CALL_NOSERIAL;
+    return ok();
+}
+
+ScopedAStatus RadioModem::sendDeviceState(int32_t serial, aidl::DeviceStateType type, bool state) {
+    LOG_CALL_IGNORED << type << ' ' << state;
+    respond()->sendDeviceStateResponse(noError(serial));
+    return ok();
+}
+
+ScopedAStatus RadioModem::setRadioCapability(int32_t serial, const aidl::RadioCapability& rc) {
+    LOG_NOT_SUPPORTED << rc;
+    respond()->setRadioCapabilityResponse(notSupported(serial), {});
+    return ok();
+}
+
+ScopedAStatus RadioModem::setRadioPower(int32_t serial, bool powerOn, bool forEmergencyCall,
+                                        bool preferredForEmergencyCall) {
+    LOG_CALL_IGNORED << powerOn << " " << forEmergencyCall << " " << preferredForEmergencyCall;
+    respond()->setRadioPowerResponse(noError(serial));
+    indicate()->radioStateChanged(RadioIndicationType::UNSOLICITED,
+                                  powerOn ? aidl::RadioState::ON : aidl::RadioState::OFF);
+    return ok();
+}
+
+ScopedAStatus RadioModem::setResponseFunctions(
+        const std::shared_ptr<aidl::IRadioModemResponse>& response,
+        const std::shared_ptr<aidl::IRadioModemIndication>& indication) {
+    LOG_CALL_NOSERIAL << response << ' ' << indication;
+    CHECK(response);
+    CHECK(indication);
+    respond = mResponseTracker =
+            ndk::SharedRefBase::make<RadioModemResponseTracker>(ref<aidl::IRadioModem>(), response);
+    indicate = indication;
+
+    indicate()->rilConnected(RadioIndicationType::UNSOLICITED);
+    indicate()->radioStateChanged(RadioIndicationType::UNSOLICITED, aidl::RadioState::ON);
+
+    return ok();
+}
+
+}  // namespace android::hardware::radio::minimal
diff --git a/radio/aidl/minradio/libminradio/modem/RadioModemResponseTracker.cpp b/radio/aidl/minradio/libminradio/modem/RadioModemResponseTracker.cpp
new file mode 100644
index 0000000..eb9bcf7
--- /dev/null
+++ b/radio/aidl/minradio/libminradio/modem/RadioModemResponseTracker.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+// see assert2_no_op in ResponseTracker.cpp
+#define __assert2 assert2_no_op
+#define __noreturn__ const
+#include <aidl/android/hardware/radio/modem/BnRadioModemResponse.h>
+#undef __assert2
+#undef __noreturn__
+#include <cassert>
+
+#include <libminradio/modem/RadioModemResponseTracker.h>
+
+#include <libminradio/debug.h>
+
+#define RADIO_MODULE "ModemResponse"
+
+namespace android::hardware::radio::minimal {
+
+using namespace ::android::hardware::radio::minimal::binder_printing;
+using ::aidl::android::hardware::radio::RadioResponseInfo;
+using ::ndk::ScopedAStatus;
+namespace aidl = ::aidl::android::hardware::radio::modem;
+
+RadioModemResponseTracker::RadioModemResponseTracker(
+        std::shared_ptr<aidl::IRadioModem> req,
+        const std::shared_ptr<aidl::IRadioModemResponse>& resp)
+    : ResponseTracker(req, resp) {}
+
+ResponseTrackerResult<aidl::ImeiInfo> RadioModemResponseTracker::getImei() {
+    auto serial = newSerial();
+    if (auto status = request()->getImei(serial); !status.isOk()) return status;
+    return getResult<aidl::ImeiInfo>(serial);
+}
+
+ScopedAStatus RadioModemResponseTracker::getImeiResponse(
+        const RadioResponseInfo& info, const std::optional<aidl::ImeiInfo>& respData) {
+    LOG_CALL_RESPONSE << respData;
+    if (isTracked(info.serial)) return handle(info, respData.value_or(aidl::ImeiInfo{}));
+    return IRadioModemResponseDelegator::getImeiResponse(info, respData);
+}
+
+}  // namespace android::hardware::radio::minimal