• 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 
17 #include <libminradio/ResponseTracker.h>
18 
19 #include <libminradio/debug.h>
20 
21 #include <random>
22 
23 namespace android::hardware::radio::minimal {
24 
25 using namespace ::android::hardware::radio::minimal::binder_printing;
26 using ::aidl::android::hardware::radio::RadioError;
27 using ::aidl::android::hardware::radio::RadioResponseInfo;
28 using ::ndk::ScopedAStatus;
29 
toError(const ScopedAStatus & status)30 RadioError ResponseTrackerResultBase::toError(const ScopedAStatus& status) {
31     CHECK(!status.isOk()) << "statusToError called with no error";
32     return RadioError::GENERIC_FAILURE;
33 }
34 
ResponseTrackerResultBase(const char * descriptor)35 ResponseTrackerResultBase::ResponseTrackerResultBase(const char* descriptor)
36     : ResponseTrackerResultBase(descriptor, RadioError::RADIO_NOT_AVAILABLE) {}
37 
ResponseTrackerResultBase(const char * descriptor,RadioError error)38 ResponseTrackerResultBase::ResponseTrackerResultBase(const char* descriptor, RadioError error)
39     : mDescriptor(descriptor), mError(error) {}
40 
ResponseTrackerResultBase(const char * descriptor,ScopedAStatus st)41 ResponseTrackerResultBase::ResponseTrackerResultBase(const char* descriptor, ScopedAStatus st)
42     : ResponseTrackerResultBase(descriptor, toError(st)) {}
43 
isOk() const44 bool ResponseTrackerResultBase::isOk() const {
45     return mError == RadioError::NONE;
46 }
47 
expectOk() const48 bool ResponseTrackerResultBase::expectOk() const {
49     if (isOk()) return true;
50     LOG(ERROR) << "Request for " << mDescriptor << " failed: " << mError;
51     return false;
52 }
53 
getError() const54 RadioError ResponseTrackerResultBase::getError() const {
55     return mError;
56 }
57 
getDescriptor() const58 const char* ResponseTrackerResultBase::getDescriptor() const {
59     return mDescriptor;
60 }
61 
ScopedSerial(int32_t serial,ResponseTrackerBase * tracker)62 ResponseTrackerBase::ScopedSerial::ScopedSerial(int32_t serial, ResponseTrackerBase* tracker)
63     : mSerial(serial), mTracker(tracker) {}
64 
~ScopedSerial()65 ResponseTrackerBase::ScopedSerial::~ScopedSerial() {
66     if (mIsReleased) return;
67     mTracker->cancelTracking(*this);
68 }
69 
operator int32_t() const70 ResponseTrackerBase::ScopedSerial::operator int32_t() const {
71     CHECK(!mIsReleased) << "ScopedSerial " << mSerial << " is not valid anymore";
72     return mSerial;
73 }
74 
release()75 void ResponseTrackerBase::ScopedSerial::release() {
76     mIsReleased = true;
77 }
78 
initialSerial()79 int32_t ResponseTrackerBase::initialSerial() {
80     /* Android framework tends to start request serial numbers from 0, so let's pick something from
81      * the second quarter of int32_t negative range. This way the chance of having a conflict is
82      * closer to zero. */
83     static const int32_t rangeSize = std::abs(std::numeric_limits<int32_t>::min() / 4);
84     static const int32_t rangeStart = std::numeric_limits<int32_t>::min() + rangeSize;
85 
86     static std::random_device generator;
87     static std::uniform_int_distribution<int32_t> distribution(rangeStart, rangeStart + rangeSize);
88 
89     return distribution(generator);
90 }
91 
newSerial()92 ResponseTrackerBase::ScopedSerial ResponseTrackerBase::newSerial() {
93     std::unique_lock lck(mSerialsGuard);
94 
95     auto serial = mSerial++;
96     if (serial == 0) [[unlikely]] {
97         serial = mSerial++;
98     }
99     if constexpr (debug::kSuperCrazyVerbose) {
100         LOG(VERBOSE) << "Tracking " << serial << " internally";
101     }
102 
103     auto inserted = mTrackedSerials.emplace(serial, nullptr).second;
104     CHECK(inserted) << "Detected tracked serials conflict at " << serial;
105 
106     return {serial, this};
107 }
108 
isTracked(int32_t serial) const109 bool ResponseTrackerBase::isTracked(int32_t serial) const {
110     std::unique_lock lck(mSerialsGuard);
111     return mTrackedSerials.contains(serial);
112 }
113 
cancelTracking(ResponseTrackerBase::ScopedSerial & serial)114 void ResponseTrackerBase::cancelTracking(ResponseTrackerBase::ScopedSerial& serial) {
115     std::unique_lock lck(mSerialsGuard);
116     auto erased = mTrackedSerials.erase(serial);
117     CHECK(erased == 1) << "Couldn't cancel tracking " << serial;
118     LOG(VERBOSE) << "Cancelled tracking " << serial << " internally";
119     serial.release();
120 }
121 
handle(const RadioResponseInfo & info,std::unique_ptr<ResponseTrackerResultBase> result)122 ScopedAStatus ResponseTrackerBase::handle(const RadioResponseInfo& info,
123                                           std::unique_ptr<ResponseTrackerResultBase> result) {
124     std::unique_lock lck(mSerialsGuard);
125     if constexpr (debug::kSuperCrazyVerbose) {
126         LOG(VERBOSE) << "Handling " << info.serial << " internally (not sending to the framework)";
127     }
128 
129     auto it = mTrackedSerials.find(info.serial);
130     CHECK(it != mTrackedSerials.end()) << "Request not tracked: " << info;
131     CHECK(it->second == nullptr) << "Request already handled: " << info;
132     it->second = std::move(result);
133 
134     return ScopedAStatus::ok();
135 }
136 
getResultBase(ResponseTrackerBase::ScopedSerial & serial)137 std::unique_ptr<ResponseTrackerResultBase> ResponseTrackerBase::getResultBase(
138         ResponseTrackerBase::ScopedSerial& serial) {
139     std::unique_lock lck(mSerialsGuard);
140     auto node = mTrackedSerials.extract(serial);
141     CHECK(node.key()) << "Request " << serial << " is not tracked";
142     if (!node.mapped()) {
143         LOG(WARNING) << "Didn't get result for " << serial
144                      << ". It may either mean setResponseFunctions has reset the callbacks or"
145                         " the callback wasn't called synchronously from the scope of "
146                         "request method implementation.";
147         serial.release();
148         return nullptr;
149     }
150     if constexpr (debug::kSuperCrazyVerbose) {
151         LOG(VERBOSE) << "Finished tracking " << serial << " internally";
152     }
153     serial.release();
154     return std::move(node.mapped());
155 }
156 
157 // This symbol silences "Mismatched versions of delegator and implementation" errors from Delegator
158 // implementation. In this specific case, Delegators are used to encapsulate incoming callbacks, not
159 // outgoing interfaces - so clamping delegator interface version to lower than implementation's
160 // version wouldn't make any difference - the local binary wouldn't know what to do with a newer
161 // interface anyways. This happens when Radio HAL (which includes callback interfaces) defined on
162 // system partition is newer than one used to build local binary (usually on vendor partition).
assert2_no_op(const char *,int,const char *,const char *)163 extern "C" void assert2_no_op(const char*, int, const char*, const char*) {}
164 
165 }  // namespace android::hardware::radio::minimal
166