• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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