1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include <aidl/android/hardware/radio/RadioError.h> 19 #include <aidl/android/hardware/radio/RadioResponseInfo.h> 20 #include <android-base/logging.h> 21 #include <android-base/thread_annotations.h> 22 #include <android/binder_auto_utils.h> 23 #include <libminradio/binder_printing.h> 24 25 #include <map> 26 #include <memory> 27 28 namespace android::hardware::radio::minimal { 29 30 class ResponseTrackerResultBase { 31 private: 32 const char* mDescriptor; 33 ::aidl::android::hardware::radio::RadioError mError; 34 35 static ::aidl::android::hardware::radio::RadioError toError(const ::ndk::ScopedAStatus& status); 36 37 protected: 38 ResponseTrackerResultBase(const char* descriptor); 39 ResponseTrackerResultBase(const char* descriptor, 40 ::aidl::android::hardware::radio::RadioError error); 41 ResponseTrackerResultBase(const char* descriptor, ::ndk::ScopedAStatus st); 42 43 public: 44 virtual ~ResponseTrackerResultBase() = default; 45 46 bool isOk() const; 47 bool expectOk() const; 48 ::aidl::android::hardware::radio::RadioError getError() const; 49 const char* getDescriptor() const; 50 }; 51 52 template <typename ResultData> 53 class ResponseTrackerResult : public ResponseTrackerResultBase { 54 private: 55 ResultData mResultData; 56 57 public: ResponseTrackerResult()58 ResponseTrackerResult() : ResponseTrackerResultBase(ResultData::descriptor) {} ResponseTrackerResult(::ndk::ScopedAStatus st)59 ResponseTrackerResult(::ndk::ScopedAStatus st) 60 : ResponseTrackerResultBase(ResultData::descriptor, std::move(st)) {} ResponseTrackerResult(ResultData data,::aidl::android::hardware::radio::RadioError error)61 ResponseTrackerResult(ResultData data, ::aidl::android::hardware::radio::RadioError error) 62 : ResponseTrackerResultBase(ResultData::descriptor, error), mResultData(data) {} 63 get()64 const ResultData& get() const { 65 CHECK(expectOk()) << "Request failed"; 66 return mResultData; 67 } 68 const ResultData& operator*() const { return get(); } 69 const ResultData* operator->() const { return &get(); } 70 }; 71 72 template <typename ResultData> 73 std::ostream& operator<<(std::ostream& os, const ResponseTrackerResult<ResultData>& val) { 74 using namespace ::android::hardware::radio::minimal::binder_printing; 75 if (val.isOk()) { 76 return os << *val; 77 } else { 78 return os << "ResponseTrackerResult<" << val.getDescriptor() // 79 << ">{error=" << val.getError() << "}"; 80 } 81 } 82 83 class ResponseTrackerBase { 84 protected: 85 class ScopedSerial; 86 87 private: 88 mutable std::mutex mSerialsGuard; 89 int32_t mSerial GUARDED_BY(mSerialsGuard) = initialSerial(); 90 std::map<int32_t, std::unique_ptr<ResponseTrackerResultBase>> mTrackedSerials 91 GUARDED_BY(mSerialsGuard); 92 93 static int32_t initialSerial(); 94 ::ndk::ScopedAStatus handle(const ::aidl::android::hardware::radio::RadioResponseInfo& info, 95 std::unique_ptr<ResponseTrackerResultBase> result); 96 std::unique_ptr<ResponseTrackerResultBase> getResultBase(ScopedSerial& serial); 97 98 protected: 99 class ScopedSerial { 100 private: 101 int32_t mSerial; 102 bool mIsReleased = false; 103 104 /* Raw pointer to allow ResponseTrackerBase self-reference. DISALLOW_COPY_AND_ASSIGN and 105 * protected status of newSerial ensures ScopedSerial won't outlive mTracker. */ 106 ResponseTrackerBase* mTracker; 107 108 DISALLOW_COPY_AND_ASSIGN(ScopedSerial); 109 110 public: 111 ScopedSerial(int32_t serial, ResponseTrackerBase* tracker); 112 ~ScopedSerial(); 113 operator int32_t() const; 114 void release(); 115 }; 116 117 ScopedSerial newSerial(); 118 bool isTracked(int32_t serial) const; 119 void cancelTracking(ScopedSerial& serial); 120 121 template <typename ResultData> handle(const::aidl::android::hardware::radio::RadioResponseInfo & info,const ResultData & data)122 ::ndk::ScopedAStatus handle(const ::aidl::android::hardware::radio::RadioResponseInfo& info, 123 const ResultData& data) { 124 std::unique_ptr<ResponseTrackerResultBase> result = 125 std::make_unique<ResponseTrackerResult<ResultData>>(data, info.error); 126 return handle(info, std::move(result)); 127 } 128 129 template <typename ResultData> getResult(ScopedSerial & serial)130 ResponseTrackerResult<ResultData> getResult(ScopedSerial& serial) { 131 auto baseResult = getResultBase(serial); 132 if (!baseResult) return {}; 133 CHECK(baseResult->getDescriptor() == ResultData::descriptor) 134 << "Failed to get ResponseTracker result. Expected " << ResultData::descriptor 135 << ", but got " << baseResult->getDescriptor(); 136 return static_cast<ResponseTrackerResult<ResultData>&>(*baseResult); 137 } 138 }; 139 140 template <typename RequestInterface, typename ResponseInterface> 141 class ResponseTracker : public ResponseInterface::DefaultDelegator, protected ResponseTrackerBase { 142 private: 143 std::weak_ptr<RequestInterface> mRequest; 144 145 protected: request()146 std::shared_ptr<RequestInterface> request() { 147 auto req = mRequest.lock(); 148 CHECK(req) << "request() should only be called from RequestInterface context! " 149 << "Failing this check means RequestInterface has been free'd."; 150 return req; 151 } 152 153 public: ResponseTracker(std::shared_ptr<RequestInterface> req,const std::shared_ptr<ResponseInterface> & resp)154 ResponseTracker(std::shared_ptr<RequestInterface> req, 155 const std::shared_ptr<ResponseInterface>& resp) 156 : ResponseInterface::DefaultDelegator(resp), mRequest(req) {} 157 }; 158 159 template <typename ResponseTrackerT> 160 class ResponseTrackerHolder { 161 private: 162 mutable std::mutex mResponseTrackerGuard; 163 std::shared_ptr<ResponseTrackerT> mTracker GUARDED_BY(mResponseTrackerGuard); 164 165 public: 166 operator bool() const { 167 std::unique_lock lck(mResponseTrackerGuard); 168 return mTracker != nullptr; 169 } 170 171 ResponseTrackerHolder& operator=(std::shared_ptr<ResponseTrackerT> tracker) { 172 std::unique_lock lck(mResponseTrackerGuard); 173 mTracker = std::move(tracker); 174 return *this; 175 } 176 operator()177 std::shared_ptr<ResponseTrackerT> operator()() const { 178 std::unique_lock lck(mResponseTrackerGuard); 179 return mTracker; 180 } 181 get()182 std::shared_ptr<ResponseTrackerT> get() const { 183 std::unique_lock lck(mResponseTrackerGuard); 184 return mTracker; 185 } 186 }; 187 188 } // namespace android::hardware::radio::minimal 189