blob: 38a9974771ae6a35320fb36f5599e6a831822a02 [file] [log] [blame]
Tomasz Wasilczyk87329672019-07-12 11:43:00 -07001/*
2 * Copyright (C) 2019 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 "CanBus.h"
18
19#include "CloseHandle.h"
20
21#include <android-base/logging.h>
22#include <libnetdevice/can.h>
23#include <libnetdevice/libnetdevice.h>
24#include <linux/can.h>
25
26namespace android {
27namespace hardware {
28namespace automotive {
29namespace can {
30namespace V1_0 {
31namespace implementation {
32
33/**
34 * Whether to log sent/received packets.
35 */
36static constexpr bool kSuperVerbose = false;
37
38Return<Result> CanBus::send(const CanMessage& message) {
39 std::lock_guard<std::mutex> lck(mIsUpGuard);
40 if (!mIsUp) return Result::INTERFACE_DOWN;
41
42 if (UNLIKELY(kSuperVerbose)) {
43 LOG(VERBOSE) << "Sending " << toString(message);
44 }
45
46 if (message.payload.size() > CAN_MAX_DLEN) return Result::PAYLOAD_TOO_LONG;
47
48 struct canfd_frame frame = {};
49 frame.can_id = message.id;
50 frame.len = message.payload.size();
51 memcpy(frame.data, message.payload.data(), message.payload.size());
52
53 if (!mSocket->send(frame)) return Result::TRANSMISSION_FAILURE;
54
55 return Result::OK;
56}
57
58Return<void> CanBus::listen(const hidl_vec<CanMessageFilter>& filter,
59 const sp<ICanMessageListener>& listenerCb, listen_cb _hidl_cb) {
60 std::lock_guard<std::mutex> lck(mIsUpGuard);
61
62 if (listenerCb == nullptr) {
63 _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
64 return {};
65 }
66 if (!mIsUp) {
67 _hidl_cb(Result::INTERFACE_DOWN, nullptr);
68 return {};
69 }
70
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080071 std::lock_guard<std::mutex> lckListeners(mMsgListenersGuard);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070072
73 sp<CloseHandle> closeHandle = new CloseHandle([this, listenerCb]() {
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080074 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
75 std::erase_if(mMsgListeners, [&](const auto& e) { return e.callback == listenerCb; });
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070076 });
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080077 mMsgListeners.emplace_back(CanMessageListener{listenerCb, filter, closeHandle});
78 auto& listener = mMsgListeners.back();
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070079
80 // fix message IDs to have all zeros on bits not covered by mask
81 std::for_each(listener.filter.begin(), listener.filter.end(),
82 [](auto& rule) { rule.id &= rule.mask; });
83
84 _hidl_cb(Result::OK, closeHandle);
85 return {};
86}
87
88CanBus::CanBus(const std::string& ifname) : mIfname(ifname) {}
89
90CanBus::~CanBus() {
91 std::lock_guard<std::mutex> lck(mIsUpGuard);
92 CHECK(!mIsUp) << "Interface is still up while being destroyed";
93
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080094 std::lock_guard<std::mutex> lckListeners(mMsgListenersGuard);
95 CHECK(mMsgListeners.empty()) << "Listener list is not empty while interface is being destroyed";
96}
97
98void CanBus::setErrorCallback(ErrorCallback errcb) {
99 CHECK(!mIsUp) << "Can't set error callback while interface is up";
100 CHECK(mErrCb == nullptr) << "Error callback is already set";
101 mErrCb = errcb;
102 CHECK(!mIsUp) << "Can't set error callback while interface is up";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700103}
104
105ICanController::Result CanBus::preUp() {
106 return ICanController::Result::OK;
107}
108
109bool CanBus::postDown() {
110 return true;
111}
112
113ICanController::Result CanBus::up() {
114 std::lock_guard<std::mutex> lck(mIsUpGuard);
115
116 if (mIsUp) {
117 LOG(WARNING) << "Interface is already up";
118 return ICanController::Result::INVALID_STATE;
119 }
120
121 const auto preResult = preUp();
122 if (preResult != ICanController::Result::OK) return preResult;
123
124 const auto isUp = netdevice::isUp(mIfname);
125 if (!isUp.has_value()) {
126 // preUp() should prepare the interface (either create or make sure it's there)
127 LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
128 return ICanController::Result::BAD_ADDRESS;
129 }
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700130
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800131 if (!*isUp && !netdevice::up(mIfname)) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700132 LOG(ERROR) << "Can't bring " << mIfname << " up";
133 return ICanController::Result::UNKNOWN_ERROR;
134 }
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800135 mDownAfterUse = !*isUp;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700136
137 using namespace std::placeholders;
138 CanSocket::ReadCallback rdcb = std::bind(&CanBus::onRead, this, _1, _2);
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800139 CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this, _1);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700140 mSocket = CanSocket::open(mIfname, rdcb, errcb);
141 if (!mSocket) {
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800142 if (mDownAfterUse) netdevice::down(mIfname);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700143 return ICanController::Result::UNKNOWN_ERROR;
144 }
145
146 mIsUp = true;
147 return ICanController::Result::OK;
148}
149
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800150void CanBus::clearMsgListeners() {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700151 std::vector<wp<ICloseHandle>> listenersToClose;
152 {
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800153 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
154 std::transform(mMsgListeners.begin(), mMsgListeners.end(),
155 std::back_inserter(listenersToClose),
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700156 [](const auto& e) { return e.closeHandle; });
157 }
158
159 for (auto& weakListener : listenersToClose) {
160 /* Between populating listenersToClose and calling close method here, some listeners might
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800161 * have been already removed from the original mMsgListeners list (resulting in a dangling
162 * weak pointer here). It's fine - we just want to clean them up. */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700163 auto listener = weakListener.promote();
164 if (listener != nullptr) listener->close();
165 }
166
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800167 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
168 CHECK(mMsgListeners.empty()) << "Listeners list wasn't emptied";
169}
170
171void CanBus::clearErrListeners() {
172 std::lock_guard<std::mutex> lck(mErrListenersGuard);
173 mErrListeners.clear();
174}
175
176Return<sp<ICloseHandle>> CanBus::listenForErrors(const sp<ICanErrorListener>& listener) {
177 if (listener == nullptr) {
178 return new CloseHandle();
179 }
180
181 std::lock_guard<std::mutex> upLck(mIsUpGuard);
182 if (!mIsUp) {
183 listener->onError(ErrorEvent::INTERFACE_DOWN, true);
184 return new CloseHandle();
185 }
186
187 std::lock_guard<std::mutex> errLck(mErrListenersGuard);
188 mErrListeners.emplace_back(listener);
189
190 return new CloseHandle([this, listener]() {
191 std::lock_guard<std::mutex> lck(mErrListenersGuard);
192 std::erase(mErrListeners, listener);
193 });
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700194}
195
196bool CanBus::down() {
197 std::lock_guard<std::mutex> lck(mIsUpGuard);
198
199 if (!mIsUp) {
200 LOG(WARNING) << "Interface is already down";
201 return false;
202 }
203 mIsUp = false;
204
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800205 clearMsgListeners();
206 clearErrListeners();
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700207 mSocket.reset();
208
209 bool success = true;
210
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800211 if (mDownAfterUse && !netdevice::down(mIfname)) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700212 LOG(ERROR) << "Can't bring " << mIfname << " down";
213 // don't return yet, let's try to do best-effort cleanup
214 success = false;
215 }
216
217 if (!postDown()) success = false;
218
219 return success;
220}
221
222/**
223 * Match the filter set against message id.
224 *
225 * For details on the filters syntax, please see CanMessageFilter at
226 * the HAL definition (types.hal).
227 *
228 * \param filter Filter to match against
229 * \param id Message id to filter
230 * \return true if the message id matches the filter, false otherwise
231 */
232static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id) {
233 if (filter.size() == 0) return true;
234
235 bool anyNonInvertedPresent = false;
236 bool anyNonInvertedSatisfied = false;
237 for (auto& rule : filter) {
238 const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted;
239 if (rule.inverted) {
240 // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set.
241 if (!satisfied) return false;
242 } else {
243 anyNonInvertedPresent = true;
244 if (satisfied) anyNonInvertedSatisfied = true;
245 }
246 }
247 return !anyNonInvertedPresent || anyNonInvertedSatisfied;
248}
249
250void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) {
251 CanMessage message = {};
252 message.id = frame.can_id;
253 message.payload = hidl_vec<uint8_t>(frame.data, frame.data + frame.len);
254 message.timestamp = timestamp.count();
255
256 if (UNLIKELY(kSuperVerbose)) {
257 LOG(VERBOSE) << "Got message " << toString(message);
258 }
259
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800260 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
261 for (auto& listener : mMsgListeners) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700262 if (!match(listener.filter, message.id)) continue;
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800263 if (!listener.callback->onReceive(message).isOk() && !listener.failedOnce) {
264 listener.failedOnce = true;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700265 LOG(WARNING) << "Failed to notify listener about message";
266 }
267 }
268}
269
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800270void CanBus::onError(int errnoVal) {
271 auto eventType = ErrorEvent::HARDWARE_ERROR;
272
273 if (errnoVal == ENODEV || errnoVal == ENETDOWN) {
274 mDownAfterUse = false;
275 eventType = ErrorEvent::INTERFACE_DOWN;
276 }
277
278 {
279 std::lock_guard<std::mutex> lck(mErrListenersGuard);
280 for (auto& listener : mErrListeners) {
281 if (!listener->onError(eventType, true).isOk()) {
282 LOG(WARNING) << "Failed to notify listener about error";
283 }
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700284 }
285 }
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800286
287 const auto errcb = mErrCb;
288 if (errcb != nullptr) errcb();
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700289}
290
291} // namespace implementation
292} // namespace V1_0
293} // namespace can
294} // namespace automotive
295} // namespace hardware
296} // namespace android