Merge cherrypicks of ['googleplex-android-review.googlesource.com/32715179', 'googleplex-android-review.googlesource.com/32768601'] into 25Q2-release.

Change-Id: Icc9917c4ea65c8425b85dcf771fc65225c9c39e5
diff --git a/radio/aidl/minradio/libminradio/RadioSlotBase.cpp b/radio/aidl/minradio/libminradio/RadioSlotBase.cpp
index 0f4bd68..07febc7 100644
--- a/radio/aidl/minradio/libminradio/RadioSlotBase.cpp
+++ b/radio/aidl/minradio/libminradio/RadioSlotBase.cpp
@@ -20,4 +20,15 @@
 
 RadioSlotBase::RadioSlotBase(std::shared_ptr<SlotContext> context) : mContext(context) {}
 
+void RadioSlotBase::setResponseFunctionsBase() {
+    mHasResponseFunctions = true;
+    if (mContext->isConnected()) onUpdatedResponseFunctions();
+}
+
+void RadioSlotBase::onUpdatedResponseFunctions() {}
+
+void RadioSlotBase::onConnected() {
+    if (mHasResponseFunctions) setResponseFunctionsBase();
+}
+
 }  // namespace android::hardware::radio::minimal
diff --git a/radio/aidl/minradio/libminradio/SlotContext.cpp b/radio/aidl/minradio/libminradio/SlotContext.cpp
index cffc178..58dbc8d 100644
--- a/radio/aidl/minradio/libminradio/SlotContext.cpp
+++ b/radio/aidl/minradio/libminradio/SlotContext.cpp
@@ -16,12 +16,33 @@
 
 #include <libminradio/SlotContext.h>
 
+#include <android-base/logging.h>
+#include <libminradio/RadioSlotBase.h>
+
 namespace android::hardware::radio::minimal {
 
 SlotContext::SlotContext(unsigned slotIndex) : mSlotIndex(slotIndex) {}
 
+void SlotContext::setConnected() {
+    CHECK(!mIsConnected) << "Can't setConnected twice";
+    mIsConnected = true;
+    for (auto weakHal : mHals) {
+        auto hal = weakHal.lock();
+        if (!hal) continue;
+        hal->onConnected();
+    }
+}
+
+bool SlotContext::isConnected() const {
+    return mIsConnected;
+}
+
 unsigned SlotContext::getSlotIndex() const {
     return mSlotIndex;
 }
 
+void SlotContext::addHal(std::weak_ptr<RadioSlotBase> hal) {
+    mHals.push_back(hal);
+}
+
 }  // namespace android::hardware::radio::minimal
diff --git a/radio/aidl/minradio/libminradio/data/RadioData.cpp b/radio/aidl/minradio/libminradio/data/RadioData.cpp
index a096c82..b5d8f66 100644
--- a/radio/aidl/minradio/libminradio/data/RadioData.cpp
+++ b/radio/aidl/minradio/libminradio/data/RadioData.cpp
@@ -137,6 +137,7 @@
     CHECK(indication);
     respond = response;
     indicate = indication;
+    setResponseFunctionsBase();
     return ok();
 }
 
diff --git a/radio/aidl/minradio/libminradio/include/libminradio/RadioSlotBase.h b/radio/aidl/minradio/libminradio/include/libminradio/RadioSlotBase.h
index d46357e..06c0fc6 100644
--- a/radio/aidl/minradio/libminradio/include/libminradio/RadioSlotBase.h
+++ b/radio/aidl/minradio/libminradio/include/libminradio/RadioSlotBase.h
@@ -22,11 +22,28 @@
 namespace android::hardware::radio::minimal {
 
 class RadioSlotBase {
+  private:
+    bool mHasResponseFunctions = false;
+
   protected:
     std::shared_ptr<SlotContext> mContext;
 
+    void setResponseFunctionsBase();
+
+    /**
+     * Called when new response functions are set. This is the place to send initial indications,
+     * such as rilConnected or radioStateChanged.
+     *
+     * This callback is deferred if the RIL is not connected. In such case, it will be called after
+     * getting rilConnected indication.
+     */
+    virtual void onUpdatedResponseFunctions();
+
   public:
     RadioSlotBase(std::shared_ptr<SlotContext> context);
+    virtual ~RadioSlotBase() = default;
+
+    void onConnected();
 };
 
 }  // namespace android::hardware::radio::minimal
diff --git a/radio/aidl/minradio/libminradio/include/libminradio/ResponseTracker.h b/radio/aidl/minradio/libminradio/include/libminradio/ResponseTracker.h
index 978d64c..a8f564e 100644
--- a/radio/aidl/minradio/libminradio/include/libminradio/ResponseTracker.h
+++ b/radio/aidl/minradio/libminradio/include/libminradio/ResponseTracker.h
@@ -56,14 +56,10 @@
 
   public:
     ResponseTrackerResult() : ResponseTrackerResultBase(ResultData::descriptor) {}
-    ResponseTrackerResult(::aidl::android::hardware::radio::RadioError error)
-        : ResponseTrackerResultBase(ResultData::descriptor, error) {}
     ResponseTrackerResult(::ndk::ScopedAStatus st)
         : ResponseTrackerResultBase(ResultData::descriptor, std::move(st)) {}
-    ResponseTrackerResult(ResultData data)
-        : ResponseTrackerResultBase(ResultData::descriptor,
-                                    ::aidl::android::hardware::radio::RadioError::NONE),
-          mResultData(data) {}
+    ResponseTrackerResult(ResultData data, ::aidl::android::hardware::radio::RadioError error)
+        : ResponseTrackerResultBase(ResultData::descriptor, error), mResultData(data) {}
 
     const ResultData& get() const {
         CHECK(expectOk()) << "Request failed";
@@ -126,7 +122,7 @@
     ::ndk::ScopedAStatus handle(const ::aidl::android::hardware::radio::RadioResponseInfo& info,
                                 const ResultData& data) {
         std::unique_ptr<ResponseTrackerResultBase> result =
-                std::make_unique<ResponseTrackerResult<ResultData>>(data);
+                std::make_unique<ResponseTrackerResult<ResultData>>(data, info.error);
         return handle(info, std::move(result));
     }
 
diff --git a/radio/aidl/minradio/libminradio/include/libminradio/SlotContext.h b/radio/aidl/minradio/libminradio/include/libminradio/SlotContext.h
index bc6f61e..c2dd7a5 100644
--- a/radio/aidl/minradio/libminradio/include/libminradio/SlotContext.h
+++ b/radio/aidl/minradio/libminradio/include/libminradio/SlotContext.h
@@ -15,16 +15,31 @@
  */
 #pragma once
 
+#include <memory>
+#include <vector>
+
 namespace android::hardware::radio::minimal {
 
+class RadioSlotBase;
+
 class SlotContext {
   public:
     SlotContext(unsigned slotIndex);
 
+    /**
+     * Mark this RIL/modem as connected. This triggers communication with the framework.
+     */
+    void setConnected();
+    bool isConnected() const;
+
     unsigned getSlotIndex() const;
 
+    void addHal(std::weak_ptr<RadioSlotBase> hal);
+
   private:
+    bool mIsConnected = false;
     unsigned mSlotIndex;
+    std::vector<std::weak_ptr<RadioSlotBase>> mHals;
 };
 
 }  // namespace android::hardware::radio::minimal
diff --git a/radio/aidl/minradio/libminradio/include/libminradio/modem/RadioModem.h b/radio/aidl/minradio/libminradio/include/libminradio/modem/RadioModem.h
index fda44c8..4d77771 100644
--- a/radio/aidl/minradio/libminradio/include/libminradio/modem/RadioModem.h
+++ b/radio/aidl/minradio/libminradio/include/libminradio/modem/RadioModem.h
@@ -29,6 +29,8 @@
                std::vector<aidl::android::hardware::radio::RadioTechnology> rats);
 
   protected:
+    void onUpdatedResponseFunctions() override;
+
     ::ndk::ScopedAStatus enableModem(int32_t serial, bool on) override;
     ::ndk::ScopedAStatus getBasebandVersion(int32_t serial) override;
     ::ndk::ScopedAStatus getDeviceIdentity(int32_t serial) override;
diff --git a/radio/aidl/minradio/libminradio/include/libminradio/network/RadioNetwork.h b/radio/aidl/minradio/libminradio/include/libminradio/network/RadioNetwork.h
index 4d3505a..a75e4fd 100644
--- a/radio/aidl/minradio/libminradio/include/libminradio/network/RadioNetwork.h
+++ b/radio/aidl/minradio/libminradio/include/libminradio/network/RadioNetwork.h
@@ -30,6 +30,7 @@
 
   protected:
     std::vector<::aidl::android::hardware::radio::network::CellInfo> getCellInfoListBase();
+    void onUpdatedResponseFunctions() override;
 
     ::ndk::ScopedAStatus getAllowedNetworkTypesBitmap(int32_t serial) override;
     ::ndk::ScopedAStatus getAvailableBandModes(int32_t serial) override;
diff --git a/radio/aidl/minradio/libminradio/include/libminradio/response.h b/radio/aidl/minradio/libminradio/include/libminradio/response.h
index 5692628..57cf4a7 100644
--- a/radio/aidl/minradio/libminradio/include/libminradio/response.h
+++ b/radio/aidl/minradio/libminradio/include/libminradio/response.h
@@ -25,4 +25,16 @@
 aidl::android::hardware::radio::RadioResponseInfo errorResponse(
         int32_t serial, aidl::android::hardware::radio::RadioError error);
 
+#define RESPOND_ERROR_IF_NOT_CONNECTED(responseMethod, ...) \
+    if (!mContext->isConnected()) RESPOND_NOT_CONNECTED(responseMethod, __VA_ARGS__);
+
+#define RESPOND_NOT_CONNECTED(responseMethod, ...)                                          \
+    {                                                                                       \
+        LOG(WARNING) << (RADIO_MODULE ".") << __func__ << " called before rilConnected";    \
+        const auto responseInfo = ::android::hardware::radio::minimal::errorResponse(       \
+                serial, ::aidl::android::hardware::radio::RadioError::RADIO_NOT_AVAILABLE); \
+        respond()->responseMethod(responseInfo __VA_OPT__(, ) __VA_ARGS__);                 \
+        return ok();                                                                        \
+    }
+
 }  // namespace android::hardware::radio::minimal
diff --git a/radio/aidl/minradio/libminradio/modem/RadioModem.cpp b/radio/aidl/minradio/libminradio/modem/RadioModem.cpp
index f29cd39..f5feaf4 100644
--- a/radio/aidl/minradio/libminradio/modem/RadioModem.cpp
+++ b/radio/aidl/minradio/libminradio/modem/RadioModem.cpp
@@ -190,11 +190,13 @@
     CHECK(indication);
     respond = response;
     indicate = indication;
+    setResponseFunctionsBase();
+    return ok();
+}
 
+void RadioModem::onUpdatedResponseFunctions() {
     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/network/RadioNetwork.cpp b/radio/aidl/minradio/libminradio/network/RadioNetwork.cpp
index e2d2a56..c6214cf 100644
--- a/radio/aidl/minradio/libminradio/network/RadioNetwork.cpp
+++ b/radio/aidl/minradio/libminradio/network/RadioNetwork.cpp
@@ -76,6 +76,7 @@
 
 ScopedAStatus RadioNetwork::getCellInfoList(int32_t serial) {
     LOG_CALL;
+    RESPOND_ERROR_IF_NOT_CONNECTED(getCellInfoListResponse, {});
     respond()->getCellInfoListResponse(noError(serial), getCellInfoListBase());
     return ok();
 }
@@ -216,7 +217,11 @@
             ref<aidl::IRadioNetwork>(), response);
     respond = mResponseTracker.get();
     indicate = indication;
+    setResponseFunctionsBase();
+    return ok();
+}
 
+void RadioNetwork::onUpdatedResponseFunctions() {
     indicate()->cellInfoList(RadioIndicationType::UNSOLICITED, getCellInfoListBase());
     auto signalStrengthResponse = mResponseTracker()->getSignalStrength();
     if (signalStrengthResponse.expectOk()) {
@@ -238,8 +243,6 @@
             }
         }).detach();
     }
-
-    return ok();
 }
 
 ScopedAStatus RadioNetwork::setSignalStrengthReportingCriteria(
diff --git a/radio/aidl/minradio/libminradio/sim/RadioSim.cpp b/radio/aidl/minradio/libminradio/sim/RadioSim.cpp
index 0365a88..58aa711 100644
--- a/radio/aidl/minradio/libminradio/sim/RadioSim.cpp
+++ b/radio/aidl/minradio/libminradio/sim/RadioSim.cpp
@@ -239,6 +239,7 @@
     CHECK(indication);
     respond = response;
     indicate = indication;
+    setResponseFunctionsBase();
     return ok();
 }
 
diff --git a/radio/aidl/minradio/minradio-example/service.cpp b/radio/aidl/minradio/minradio-example/service.cpp
index 6d3c020..8b6ae72 100644
--- a/radio/aidl/minradio/minradio-example/service.cpp
+++ b/radio/aidl/minradio/minradio-example/service.cpp
@@ -31,9 +31,10 @@
 static std::vector<std::shared_ptr<ndk::ICInterface>> gPublishedHals;
 
 static void publishRadioConfig() {
+    const auto instance = RadioConfig::descriptor + "/default"s;
+    LOG(DEBUG) << "Publishing " << instance;
     auto aidlHal = ndk::SharedRefBase::make<RadioConfig>();
     gPublishedHals.push_back(aidlHal);
-    const auto instance = RadioConfig::descriptor + "/default"s;
     const auto status = AServiceManager_addService(aidlHal->asBinder().get(), instance.c_str());
     CHECK_EQ(status, STATUS_OK);
 }
@@ -47,9 +48,9 @@
         return;
     }
     LOG(DEBUG) << "Publishing " << instance;
-
     auto aidlHal = ndk::SharedRefBase::make<T>(context);
     gPublishedHals.push_back(aidlHal);
+    context->addHal(aidlHal);
     const auto status = AServiceManager_addService(aidlHal->asBinder().get(), instance.c_str());
     CHECK_EQ(status, STATUS_OK);
 }
@@ -63,13 +64,15 @@
     ABinderProcess_startThreadPool();
 
     auto slot1Context = std::make_shared<minimal::SlotContext>(1);
-
     publishRadioConfig();
     publishRadioHal<RadioData>("slot1", slot1Context);
     publishRadioHal<RadioModem>("slot1", slot1Context);
     publishRadioHal<RadioNetwork>("slot1", slot1Context);
     publishRadioHal<RadioSim>("slot1", slot1Context);
 
+    // Non-virtual implementation would set up and initialize connection to the modem here
+
+    slot1Context->setConnected();
     LOG(DEBUG) << "Minimal Radio HAL service is operational";
     ABinderProcess_joinThreadPool();
     LOG(FATAL) << "Minimal Radio HAL service has stopped";