blob: 86df5dc93b2df8fa03a52d79076ac26a6fde379c [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>
chrisweirbee3d2c2019-11-19 10:23:37 -080025#include <linux/can/error.h>
26#include <linux/can/raw.h>
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070027
28namespace android {
29namespace hardware {
30namespace automotive {
31namespace can {
32namespace V1_0 {
33namespace implementation {
34
chrisweircf36cea2019-11-08 16:41:02 -080035/** Whether to log sent/received packets. */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070036static 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
chrisweircf36cea2019-11-08 16:41:02 -080088CanBus::CanBus() {}
89
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070090CanBus::CanBus(const std::string& ifname) : mIfname(ifname) {}
91
92CanBus::~CanBus() {
93 std::lock_guard<std::mutex> lck(mIsUpGuard);
94 CHECK(!mIsUp) << "Interface is still up while being destroyed";
95
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080096 std::lock_guard<std::mutex> lckListeners(mMsgListenersGuard);
97 CHECK(mMsgListeners.empty()) << "Listener list is not empty while interface is being destroyed";
98}
99
100void CanBus::setErrorCallback(ErrorCallback errcb) {
101 CHECK(!mIsUp) << "Can't set error callback while interface is up";
102 CHECK(mErrCb == nullptr) << "Error callback is already set";
103 mErrCb = errcb;
104 CHECK(!mIsUp) << "Can't set error callback while interface is up";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700105}
106
107ICanController::Result CanBus::preUp() {
108 return ICanController::Result::OK;
109}
110
111bool CanBus::postDown() {
112 return true;
113}
114
115ICanController::Result CanBus::up() {
116 std::lock_guard<std::mutex> lck(mIsUpGuard);
117
118 if (mIsUp) {
119 LOG(WARNING) << "Interface is already up";
120 return ICanController::Result::INVALID_STATE;
121 }
122
123 const auto preResult = preUp();
124 if (preResult != ICanController::Result::OK) return preResult;
125
126 const auto isUp = netdevice::isUp(mIfname);
127 if (!isUp.has_value()) {
128 // preUp() should prepare the interface (either create or make sure it's there)
129 LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
130 return ICanController::Result::BAD_ADDRESS;
131 }
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700132
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800133 if (!*isUp && !netdevice::up(mIfname)) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700134 LOG(ERROR) << "Can't bring " << mIfname << " up";
135 return ICanController::Result::UNKNOWN_ERROR;
136 }
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800137 mDownAfterUse = !*isUp;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700138
139 using namespace std::placeholders;
140 CanSocket::ReadCallback rdcb = std::bind(&CanBus::onRead, this, _1, _2);
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800141 CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this, _1);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700142 mSocket = CanSocket::open(mIfname, rdcb, errcb);
143 if (!mSocket) {
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800144 if (mDownAfterUse) netdevice::down(mIfname);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700145 return ICanController::Result::UNKNOWN_ERROR;
146 }
147
148 mIsUp = true;
149 return ICanController::Result::OK;
150}
151
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800152void CanBus::clearMsgListeners() {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700153 std::vector<wp<ICloseHandle>> listenersToClose;
154 {
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800155 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
156 std::transform(mMsgListeners.begin(), mMsgListeners.end(),
157 std::back_inserter(listenersToClose),
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700158 [](const auto& e) { return e.closeHandle; });
159 }
160
161 for (auto& weakListener : listenersToClose) {
162 /* Between populating listenersToClose and calling close method here, some listeners might
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800163 * have been already removed from the original mMsgListeners list (resulting in a dangling
164 * weak pointer here). It's fine - we just want to clean them up. */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700165 auto listener = weakListener.promote();
166 if (listener != nullptr) listener->close();
167 }
168
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800169 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
170 CHECK(mMsgListeners.empty()) << "Listeners list wasn't emptied";
171}
172
173void CanBus::clearErrListeners() {
174 std::lock_guard<std::mutex> lck(mErrListenersGuard);
175 mErrListeners.clear();
176}
177
178Return<sp<ICloseHandle>> CanBus::listenForErrors(const sp<ICanErrorListener>& listener) {
179 if (listener == nullptr) {
180 return new CloseHandle();
181 }
182
183 std::lock_guard<std::mutex> upLck(mIsUpGuard);
184 if (!mIsUp) {
185 listener->onError(ErrorEvent::INTERFACE_DOWN, true);
186 return new CloseHandle();
187 }
188
189 std::lock_guard<std::mutex> errLck(mErrListenersGuard);
190 mErrListeners.emplace_back(listener);
191
192 return new CloseHandle([this, listener]() {
193 std::lock_guard<std::mutex> lck(mErrListenersGuard);
194 std::erase(mErrListeners, listener);
195 });
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700196}
197
198bool CanBus::down() {
199 std::lock_guard<std::mutex> lck(mIsUpGuard);
200
201 if (!mIsUp) {
202 LOG(WARNING) << "Interface is already down";
203 return false;
204 }
205 mIsUp = false;
206
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800207 clearMsgListeners();
208 clearErrListeners();
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700209 mSocket.reset();
210
211 bool success = true;
212
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800213 if (mDownAfterUse && !netdevice::down(mIfname)) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700214 LOG(ERROR) << "Can't bring " << mIfname << " down";
215 // don't return yet, let's try to do best-effort cleanup
216 success = false;
217 }
218
219 if (!postDown()) success = false;
220
221 return success;
222}
223
224/**
chrisweirbee3d2c2019-11-19 10:23:37 -0800225 * Helper function to determine if a flag meets the requirements of a
226 * FilterFlag. See definition of FilterFlag in types.hal
227 *
228 * \param filterFlag FilterFlag object to match flag against
229 * \param flag bool object from CanMessage object
230 */
231static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) {
232 // TODO(b/144458917) add testing for this to VTS tests
233 if (filterFlag == FilterFlag::DONT_CARE) return true;
234 if (filterFlag == FilterFlag::REQUIRE) return flag;
235 if (filterFlag == FilterFlag::EXCLUDE) return !flag;
236 return false;
237}
238
239/**
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700240 * Match the filter set against message id.
241 *
242 * For details on the filters syntax, please see CanMessageFilter at
243 * the HAL definition (types.hal).
244 *
245 * \param filter Filter to match against
246 * \param id Message id to filter
247 * \return true if the message id matches the filter, false otherwise
248 */
chrisweirbee3d2c2019-11-19 10:23:37 -0800249static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, bool isExtendedId,
250 bool isRtr) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700251 if (filter.size() == 0) return true;
252
253 bool anyNonInvertedPresent = false;
254 bool anyNonInvertedSatisfied = false;
255 for (auto& rule : filter) {
chrisweirbee3d2c2019-11-19 10:23:37 -0800256 const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted &&
257 satisfiesFilterFlag(rule.rtr, isRtr) &&
258 satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700259 if (rule.inverted) {
260 // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set.
261 if (!satisfied) return false;
262 } else {
263 anyNonInvertedPresent = true;
264 if (satisfied) anyNonInvertedSatisfied = true;
265 }
266 }
267 return !anyNonInvertedPresent || anyNonInvertedSatisfied;
268}
269
chrisweirbee3d2c2019-11-19 10:23:37 -0800270void CanBus::notifyErrorListeners(ErrorEvent err, bool isFatal) {
271 std::lock_guard<std::mutex> lck(mErrListenersGuard);
272 for (auto& listener : mErrListeners) {
273 if (!listener->onError(err, isFatal).isOk()) {
274 LOG(WARNING) << "Failed to notify listener about error";
275 }
276 }
277}
278
279static ErrorEvent parseErrorFrame(const struct canfd_frame& frame) {
280 // decode error frame (to a degree)
281 if ((frame.can_id & (CAN_ERR_BUSERROR | CAN_ERR_BUSOFF)) != 0) {
282 return ErrorEvent::BUS_ERROR;
283 }
284 if ((frame.data[1] & CAN_ERR_CRTL_TX_OVERFLOW) != 0) {
285 return ErrorEvent::TX_OVERFLOW;
286 }
287 if ((frame.data[1] & CAN_ERR_CRTL_RX_OVERFLOW) != 0) {
288 return ErrorEvent::RX_OVERFLOW;
289 }
290 if ((frame.data[2] & CAN_ERR_PROT_OVERLOAD) != 0) {
291 return ErrorEvent::BUS_OVERLOAD;
292 }
293 if ((frame.can_id & CAN_ERR_PROT) != 0) {
294 return ErrorEvent::MALFORMED_INPUT;
295 }
296 if ((frame.can_id & (CAN_ERR_CRTL | CAN_ERR_TRX | CAN_ERR_RESTARTED)) != 0) {
297 // "controller restarted" constitutes a HARDWARE_ERROR imo
298 return ErrorEvent::HARDWARE_ERROR;
299 }
300 return ErrorEvent::UNKNOWN_ERROR;
301}
302
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700303void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) {
chrisweirbee3d2c2019-11-19 10:23:37 -0800304 if ((frame.can_id & CAN_ERR_FLAG) != 0) {
305 // error bit is set
306 LOG(WARNING) << "CAN Error frame received";
307 // TODO(b/144458917) consider providing different values for isFatal, depending on error
308 notifyErrorListeners(parseErrorFrame(frame), false);
309 return;
310 }
311
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700312 CanMessage message = {};
chrisweirbee3d2c2019-11-19 10:23:37 -0800313 message.id = frame.can_id & CAN_EFF_MASK; // mask out eff/rtr/err flags
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700314 message.payload = hidl_vec<uint8_t>(frame.data, frame.data + frame.len);
315 message.timestamp = timestamp.count();
chrisweirbee3d2c2019-11-19 10:23:37 -0800316 message.isExtendedId = (frame.can_id & CAN_EFF_FLAG) != 0;
317 message.remoteTransmissionRequest = (frame.can_id & CAN_RTR_FLAG) != 0;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700318
319 if (UNLIKELY(kSuperVerbose)) {
320 LOG(VERBOSE) << "Got message " << toString(message);
321 }
322
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800323 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
324 for (auto& listener : mMsgListeners) {
chrisweirbee3d2c2019-11-19 10:23:37 -0800325 if (!match(listener.filter, message.id, message.remoteTransmissionRequest,
326 message.isExtendedId))
327 continue;
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800328 if (!listener.callback->onReceive(message).isOk() && !listener.failedOnce) {
329 listener.failedOnce = true;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700330 LOG(WARNING) << "Failed to notify listener about message";
331 }
332 }
333}
334
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800335void CanBus::onError(int errnoVal) {
336 auto eventType = ErrorEvent::HARDWARE_ERROR;
337
338 if (errnoVal == ENODEV || errnoVal == ENETDOWN) {
339 mDownAfterUse = false;
340 eventType = ErrorEvent::INTERFACE_DOWN;
341 }
chrisweirbee3d2c2019-11-19 10:23:37 -0800342 notifyErrorListeners(eventType, true);
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800343
344 const auto errcb = mErrCb;
345 if (errcb != nullptr) errcb();
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700346}
347
348} // namespace implementation
349} // namespace V1_0
350} // namespace can
351} // namespace automotive
352} // namespace hardware
353} // namespace android