blob: 454ab008efd2e43de285b0b5c85edd1bb89d66ec [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
Tomasz Wasilczyk55f21932019-12-20 09:20:24 -080028namespace android::hardware::automotive::can::V1_0::implementation {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070029
chrisweircf36cea2019-11-08 16:41:02 -080030/** Whether to log sent/received packets. */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070031static constexpr bool kSuperVerbose = false;
32
33Return<Result> CanBus::send(const CanMessage& message) {
34 std::lock_guard<std::mutex> lck(mIsUpGuard);
35 if (!mIsUp) return Result::INTERFACE_DOWN;
36
37 if (UNLIKELY(kSuperVerbose)) {
38 LOG(VERBOSE) << "Sending " << toString(message);
39 }
40
41 if (message.payload.size() > CAN_MAX_DLEN) return Result::PAYLOAD_TOO_LONG;
42
43 struct canfd_frame frame = {};
44 frame.can_id = message.id;
45 frame.len = message.payload.size();
46 memcpy(frame.data, message.payload.data(), message.payload.size());
47
48 if (!mSocket->send(frame)) return Result::TRANSMISSION_FAILURE;
49
50 return Result::OK;
51}
52
53Return<void> CanBus::listen(const hidl_vec<CanMessageFilter>& filter,
54 const sp<ICanMessageListener>& listenerCb, listen_cb _hidl_cb) {
55 std::lock_guard<std::mutex> lck(mIsUpGuard);
56
57 if (listenerCb == nullptr) {
58 _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
59 return {};
60 }
61 if (!mIsUp) {
62 _hidl_cb(Result::INTERFACE_DOWN, nullptr);
63 return {};
64 }
65
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080066 std::lock_guard<std::mutex> lckListeners(mMsgListenersGuard);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070067
68 sp<CloseHandle> closeHandle = new CloseHandle([this, listenerCb]() {
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080069 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
70 std::erase_if(mMsgListeners, [&](const auto& e) { return e.callback == listenerCb; });
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070071 });
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080072 mMsgListeners.emplace_back(CanMessageListener{listenerCb, filter, closeHandle});
73 auto& listener = mMsgListeners.back();
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070074
75 // fix message IDs to have all zeros on bits not covered by mask
76 std::for_each(listener.filter.begin(), listener.filter.end(),
77 [](auto& rule) { rule.id &= rule.mask; });
78
79 _hidl_cb(Result::OK, closeHandle);
80 return {};
81}
82
chrisweircf36cea2019-11-08 16:41:02 -080083CanBus::CanBus() {}
84
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070085CanBus::CanBus(const std::string& ifname) : mIfname(ifname) {}
86
87CanBus::~CanBus() {
88 std::lock_guard<std::mutex> lck(mIsUpGuard);
89 CHECK(!mIsUp) << "Interface is still up while being destroyed";
90
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080091 std::lock_guard<std::mutex> lckListeners(mMsgListenersGuard);
92 CHECK(mMsgListeners.empty()) << "Listener list is not empty while interface is being destroyed";
93}
94
95void CanBus::setErrorCallback(ErrorCallback errcb) {
96 CHECK(!mIsUp) << "Can't set error callback while interface is up";
97 CHECK(mErrCb == nullptr) << "Error callback is already set";
98 mErrCb = errcb;
99 CHECK(!mIsUp) << "Can't set error callback while interface is up";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700100}
101
102ICanController::Result CanBus::preUp() {
103 return ICanController::Result::OK;
104}
105
106bool CanBus::postDown() {
107 return true;
108}
109
110ICanController::Result CanBus::up() {
111 std::lock_guard<std::mutex> lck(mIsUpGuard);
112
113 if (mIsUp) {
114 LOG(WARNING) << "Interface is already up";
115 return ICanController::Result::INVALID_STATE;
116 }
117
118 const auto preResult = preUp();
119 if (preResult != ICanController::Result::OK) return preResult;
120
121 const auto isUp = netdevice::isUp(mIfname);
122 if (!isUp.has_value()) {
123 // preUp() should prepare the interface (either create or make sure it's there)
124 LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
125 return ICanController::Result::BAD_ADDRESS;
126 }
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700127
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800128 if (!*isUp && !netdevice::up(mIfname)) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700129 LOG(ERROR) << "Can't bring " << mIfname << " up";
130 return ICanController::Result::UNKNOWN_ERROR;
131 }
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800132 mDownAfterUse = !*isUp;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700133
134 using namespace std::placeholders;
135 CanSocket::ReadCallback rdcb = std::bind(&CanBus::onRead, this, _1, _2);
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800136 CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this, _1);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700137 mSocket = CanSocket::open(mIfname, rdcb, errcb);
138 if (!mSocket) {
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800139 if (mDownAfterUse) netdevice::down(mIfname);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700140 return ICanController::Result::UNKNOWN_ERROR;
141 }
142
143 mIsUp = true;
144 return ICanController::Result::OK;
145}
146
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800147void CanBus::clearMsgListeners() {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700148 std::vector<wp<ICloseHandle>> listenersToClose;
149 {
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800150 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
151 std::transform(mMsgListeners.begin(), mMsgListeners.end(),
152 std::back_inserter(listenersToClose),
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700153 [](const auto& e) { return e.closeHandle; });
154 }
155
156 for (auto& weakListener : listenersToClose) {
157 /* Between populating listenersToClose and calling close method here, some listeners might
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800158 * have been already removed from the original mMsgListeners list (resulting in a dangling
159 * weak pointer here). It's fine - we just want to clean them up. */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700160 auto listener = weakListener.promote();
161 if (listener != nullptr) listener->close();
162 }
163
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800164 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
165 CHECK(mMsgListeners.empty()) << "Listeners list wasn't emptied";
166}
167
168void CanBus::clearErrListeners() {
169 std::lock_guard<std::mutex> lck(mErrListenersGuard);
170 mErrListeners.clear();
171}
172
173Return<sp<ICloseHandle>> CanBus::listenForErrors(const sp<ICanErrorListener>& listener) {
174 if (listener == nullptr) {
175 return new CloseHandle();
176 }
177
178 std::lock_guard<std::mutex> upLck(mIsUpGuard);
179 if (!mIsUp) {
180 listener->onError(ErrorEvent::INTERFACE_DOWN, true);
181 return new CloseHandle();
182 }
183
184 std::lock_guard<std::mutex> errLck(mErrListenersGuard);
185 mErrListeners.emplace_back(listener);
186
187 return new CloseHandle([this, listener]() {
188 std::lock_guard<std::mutex> lck(mErrListenersGuard);
189 std::erase(mErrListeners, listener);
190 });
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700191}
192
193bool CanBus::down() {
194 std::lock_guard<std::mutex> lck(mIsUpGuard);
195
196 if (!mIsUp) {
197 LOG(WARNING) << "Interface is already down";
198 return false;
199 }
200 mIsUp = false;
201
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800202 clearMsgListeners();
203 clearErrListeners();
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700204 mSocket.reset();
205
206 bool success = true;
207
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800208 if (mDownAfterUse && !netdevice::down(mIfname)) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700209 LOG(ERROR) << "Can't bring " << mIfname << " down";
210 // don't return yet, let's try to do best-effort cleanup
211 success = false;
212 }
213
214 if (!postDown()) success = false;
215
216 return success;
217}
218
219/**
chrisweirbee3d2c2019-11-19 10:23:37 -0800220 * Helper function to determine if a flag meets the requirements of a
221 * FilterFlag. See definition of FilterFlag in types.hal
222 *
223 * \param filterFlag FilterFlag object to match flag against
224 * \param flag bool object from CanMessage object
225 */
226static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) {
227 // TODO(b/144458917) add testing for this to VTS tests
228 if (filterFlag == FilterFlag::DONT_CARE) return true;
229 if (filterFlag == FilterFlag::REQUIRE) return flag;
230 if (filterFlag == FilterFlag::EXCLUDE) return !flag;
231 return false;
232}
233
234/**
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700235 * Match the filter set against message id.
236 *
237 * For details on the filters syntax, please see CanMessageFilter at
238 * the HAL definition (types.hal).
239 *
240 * \param filter Filter to match against
241 * \param id Message id to filter
242 * \return true if the message id matches the filter, false otherwise
243 */
chrisweirbee3d2c2019-11-19 10:23:37 -0800244static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, bool isExtendedId,
245 bool isRtr) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700246 if (filter.size() == 0) return true;
247
248 bool anyNonInvertedPresent = false;
249 bool anyNonInvertedSatisfied = false;
250 for (auto& rule : filter) {
chrisweirbee3d2c2019-11-19 10:23:37 -0800251 const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted &&
252 satisfiesFilterFlag(rule.rtr, isRtr) &&
253 satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700254 if (rule.inverted) {
255 // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set.
256 if (!satisfied) return false;
257 } else {
258 anyNonInvertedPresent = true;
259 if (satisfied) anyNonInvertedSatisfied = true;
260 }
261 }
262 return !anyNonInvertedPresent || anyNonInvertedSatisfied;
263}
264
chrisweirbee3d2c2019-11-19 10:23:37 -0800265void CanBus::notifyErrorListeners(ErrorEvent err, bool isFatal) {
266 std::lock_guard<std::mutex> lck(mErrListenersGuard);
267 for (auto& listener : mErrListeners) {
268 if (!listener->onError(err, isFatal).isOk()) {
269 LOG(WARNING) << "Failed to notify listener about error";
270 }
271 }
272}
273
274static ErrorEvent parseErrorFrame(const struct canfd_frame& frame) {
275 // decode error frame (to a degree)
276 if ((frame.can_id & (CAN_ERR_BUSERROR | CAN_ERR_BUSOFF)) != 0) {
277 return ErrorEvent::BUS_ERROR;
278 }
279 if ((frame.data[1] & CAN_ERR_CRTL_TX_OVERFLOW) != 0) {
280 return ErrorEvent::TX_OVERFLOW;
281 }
282 if ((frame.data[1] & CAN_ERR_CRTL_RX_OVERFLOW) != 0) {
283 return ErrorEvent::RX_OVERFLOW;
284 }
285 if ((frame.data[2] & CAN_ERR_PROT_OVERLOAD) != 0) {
286 return ErrorEvent::BUS_OVERLOAD;
287 }
288 if ((frame.can_id & CAN_ERR_PROT) != 0) {
289 return ErrorEvent::MALFORMED_INPUT;
290 }
291 if ((frame.can_id & (CAN_ERR_CRTL | CAN_ERR_TRX | CAN_ERR_RESTARTED)) != 0) {
292 // "controller restarted" constitutes a HARDWARE_ERROR imo
293 return ErrorEvent::HARDWARE_ERROR;
294 }
295 return ErrorEvent::UNKNOWN_ERROR;
296}
297
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700298void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) {
chrisweirbee3d2c2019-11-19 10:23:37 -0800299 if ((frame.can_id & CAN_ERR_FLAG) != 0) {
300 // error bit is set
301 LOG(WARNING) << "CAN Error frame received";
302 // TODO(b/144458917) consider providing different values for isFatal, depending on error
303 notifyErrorListeners(parseErrorFrame(frame), false);
304 return;
305 }
306
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700307 CanMessage message = {};
chrisweirbee3d2c2019-11-19 10:23:37 -0800308 message.id = frame.can_id & CAN_EFF_MASK; // mask out eff/rtr/err flags
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700309 message.payload = hidl_vec<uint8_t>(frame.data, frame.data + frame.len);
310 message.timestamp = timestamp.count();
chrisweirbee3d2c2019-11-19 10:23:37 -0800311 message.isExtendedId = (frame.can_id & CAN_EFF_FLAG) != 0;
312 message.remoteTransmissionRequest = (frame.can_id & CAN_RTR_FLAG) != 0;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700313
314 if (UNLIKELY(kSuperVerbose)) {
315 LOG(VERBOSE) << "Got message " << toString(message);
316 }
317
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800318 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
319 for (auto& listener : mMsgListeners) {
chrisweirbee3d2c2019-11-19 10:23:37 -0800320 if (!match(listener.filter, message.id, message.remoteTransmissionRequest,
321 message.isExtendedId))
322 continue;
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800323 if (!listener.callback->onReceive(message).isOk() && !listener.failedOnce) {
324 listener.failedOnce = true;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700325 LOG(WARNING) << "Failed to notify listener about message";
326 }
327 }
328}
329
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800330void CanBus::onError(int errnoVal) {
331 auto eventType = ErrorEvent::HARDWARE_ERROR;
332
333 if (errnoVal == ENODEV || errnoVal == ENETDOWN) {
334 mDownAfterUse = false;
335 eventType = ErrorEvent::INTERFACE_DOWN;
336 }
chrisweirbee3d2c2019-11-19 10:23:37 -0800337 notifyErrorListeners(eventType, true);
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800338
339 const auto errcb = mErrCb;
340 if (errcb != nullptr) errcb();
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700341}
342
Tomasz Wasilczyk55f21932019-12-20 09:20:24 -0800343} // namespace android::hardware::automotive::can::V1_0::implementation