blob: 9f704c1ebdbfb7f7be7e8dcfeaf62b5cbceb503b [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;
chrisweirf53a4e22019-11-19 10:23:37 -080045 if (message.isExtendedId) frame.can_id |= CAN_EFF_FLAG;
46 if (message.remoteTransmissionRequest) frame.can_id |= CAN_RTR_FLAG;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070047 frame.len = message.payload.size();
48 memcpy(frame.data, message.payload.data(), message.payload.size());
49
50 if (!mSocket->send(frame)) return Result::TRANSMISSION_FAILURE;
51
52 return Result::OK;
53}
54
55Return<void> CanBus::listen(const hidl_vec<CanMessageFilter>& filter,
56 const sp<ICanMessageListener>& listenerCb, listen_cb _hidl_cb) {
57 std::lock_guard<std::mutex> lck(mIsUpGuard);
58
59 if (listenerCb == nullptr) {
60 _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
61 return {};
62 }
63 if (!mIsUp) {
64 _hidl_cb(Result::INTERFACE_DOWN, nullptr);
65 return {};
66 }
67
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080068 std::lock_guard<std::mutex> lckListeners(mMsgListenersGuard);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070069
70 sp<CloseHandle> closeHandle = new CloseHandle([this, listenerCb]() {
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080071 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
72 std::erase_if(mMsgListeners, [&](const auto& e) { return e.callback == listenerCb; });
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070073 });
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080074 mMsgListeners.emplace_back(CanMessageListener{listenerCb, filter, closeHandle});
75 auto& listener = mMsgListeners.back();
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070076
77 // fix message IDs to have all zeros on bits not covered by mask
78 std::for_each(listener.filter.begin(), listener.filter.end(),
79 [](auto& rule) { rule.id &= rule.mask; });
80
81 _hidl_cb(Result::OK, closeHandle);
82 return {};
83}
84
chrisweircf36cea2019-11-08 16:41:02 -080085CanBus::CanBus() {}
86
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070087CanBus::CanBus(const std::string& ifname) : mIfname(ifname) {}
88
89CanBus::~CanBus() {
90 std::lock_guard<std::mutex> lck(mIsUpGuard);
91 CHECK(!mIsUp) << "Interface is still up while being destroyed";
92
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080093 std::lock_guard<std::mutex> lckListeners(mMsgListenersGuard);
94 CHECK(mMsgListeners.empty()) << "Listener list is not empty while interface is being destroyed";
95}
96
97void CanBus::setErrorCallback(ErrorCallback errcb) {
98 CHECK(!mIsUp) << "Can't set error callback while interface is up";
99 CHECK(mErrCb == nullptr) << "Error callback is already set";
100 mErrCb = errcb;
101 CHECK(!mIsUp) << "Can't set error callback while interface is up";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700102}
103
104ICanController::Result CanBus::preUp() {
105 return ICanController::Result::OK;
106}
107
108bool CanBus::postDown() {
109 return true;
110}
111
112ICanController::Result CanBus::up() {
113 std::lock_guard<std::mutex> lck(mIsUpGuard);
114
115 if (mIsUp) {
116 LOG(WARNING) << "Interface is already up";
117 return ICanController::Result::INVALID_STATE;
118 }
119
120 const auto preResult = preUp();
121 if (preResult != ICanController::Result::OK) return preResult;
122
123 const auto isUp = netdevice::isUp(mIfname);
124 if (!isUp.has_value()) {
125 // preUp() should prepare the interface (either create or make sure it's there)
126 LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
Tomasz Wasilczykf3da9b62020-02-14 10:54:28 -0800127 return ICanController::Result::BAD_INTERFACE_ID;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700128 }
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700129
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800130 if (!*isUp && !netdevice::up(mIfname)) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700131 LOG(ERROR) << "Can't bring " << mIfname << " up";
132 return ICanController::Result::UNKNOWN_ERROR;
133 }
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800134 mDownAfterUse = !*isUp;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700135
136 using namespace std::placeholders;
137 CanSocket::ReadCallback rdcb = std::bind(&CanBus::onRead, this, _1, _2);
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800138 CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this, _1);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700139 mSocket = CanSocket::open(mIfname, rdcb, errcb);
140 if (!mSocket) {
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800141 if (mDownAfterUse) netdevice::down(mIfname);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700142 return ICanController::Result::UNKNOWN_ERROR;
143 }
144
145 mIsUp = true;
146 return ICanController::Result::OK;
147}
148
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800149void CanBus::clearMsgListeners() {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700150 std::vector<wp<ICloseHandle>> listenersToClose;
151 {
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800152 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
153 std::transform(mMsgListeners.begin(), mMsgListeners.end(),
154 std::back_inserter(listenersToClose),
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700155 [](const auto& e) { return e.closeHandle; });
156 }
157
158 for (auto& weakListener : listenersToClose) {
159 /* Between populating listenersToClose and calling close method here, some listeners might
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800160 * have been already removed from the original mMsgListeners list (resulting in a dangling
161 * weak pointer here). It's fine - we just want to clean them up. */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700162 auto listener = weakListener.promote();
163 if (listener != nullptr) listener->close();
164 }
165
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800166 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
167 CHECK(mMsgListeners.empty()) << "Listeners list wasn't emptied";
168}
169
170void CanBus::clearErrListeners() {
171 std::lock_guard<std::mutex> lck(mErrListenersGuard);
172 mErrListeners.clear();
173}
174
175Return<sp<ICloseHandle>> CanBus::listenForErrors(const sp<ICanErrorListener>& listener) {
176 if (listener == nullptr) {
177 return new CloseHandle();
178 }
179
180 std::lock_guard<std::mutex> upLck(mIsUpGuard);
181 if (!mIsUp) {
182 listener->onError(ErrorEvent::INTERFACE_DOWN, true);
183 return new CloseHandle();
184 }
185
186 std::lock_guard<std::mutex> errLck(mErrListenersGuard);
187 mErrListeners.emplace_back(listener);
188
189 return new CloseHandle([this, listener]() {
190 std::lock_guard<std::mutex> lck(mErrListenersGuard);
191 std::erase(mErrListeners, listener);
192 });
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700193}
194
195bool CanBus::down() {
196 std::lock_guard<std::mutex> lck(mIsUpGuard);
197
198 if (!mIsUp) {
199 LOG(WARNING) << "Interface is already down";
200 return false;
201 }
202 mIsUp = false;
203
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800204 clearMsgListeners();
205 clearErrListeners();
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700206 mSocket.reset();
207
208 bool success = true;
209
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800210 if (mDownAfterUse && !netdevice::down(mIfname)) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700211 LOG(ERROR) << "Can't bring " << mIfname << " down";
212 // don't return yet, let's try to do best-effort cleanup
213 success = false;
214 }
215
216 if (!postDown()) success = false;
217
218 return success;
219}
220
221/**
chrisweirbee3d2c2019-11-19 10:23:37 -0800222 * Helper function to determine if a flag meets the requirements of a
223 * FilterFlag. See definition of FilterFlag in types.hal
224 *
225 * \param filterFlag FilterFlag object to match flag against
226 * \param flag bool object from CanMessage object
227 */
228static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) {
229 // TODO(b/144458917) add testing for this to VTS tests
230 if (filterFlag == FilterFlag::DONT_CARE) return true;
chrisweirf53a4e22019-11-19 10:23:37 -0800231 if (filterFlag == FilterFlag::SET) return flag;
232 if (filterFlag == FilterFlag::NOT_SET) return !flag;
chrisweirbee3d2c2019-11-19 10:23:37 -0800233 return false;
234}
235
236/**
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700237 * Match the filter set against message id.
238 *
239 * For details on the filters syntax, please see CanMessageFilter at
240 * the HAL definition (types.hal).
241 *
242 * \param filter Filter to match against
243 * \param id Message id to filter
244 * \return true if the message id matches the filter, false otherwise
245 */
chrisweirf53a4e22019-11-19 10:23:37 -0800246static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, bool isRtr,
247 bool isExtendedId) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700248 if (filter.size() == 0) return true;
249
chrisweirf53a4e22019-11-19 10:23:37 -0800250 bool anyNonExcludeRulePresent = false;
251 bool anyNonExcludeRuleSatisfied = false;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700252 for (auto& rule : filter) {
chrisweirf53a4e22019-11-19 10:23:37 -0800253 const bool satisfied = ((id & rule.mask) == rule.id) &&
chrisweirbee3d2c2019-11-19 10:23:37 -0800254 satisfiesFilterFlag(rule.rtr, isRtr) &&
255 satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
chrisweirf53a4e22019-11-19 10:23:37 -0800256
257 if (rule.exclude) {
258 // Any excluded (blacklist) rule not being satisfied invalidates the whole filter set.
259 if (satisfied) return false;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700260 } else {
chrisweirf53a4e22019-11-19 10:23:37 -0800261 anyNonExcludeRulePresent = true;
262 if (satisfied) anyNonExcludeRuleSatisfied = true;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700263 }
264 }
chrisweirf53a4e22019-11-19 10:23:37 -0800265 return !anyNonExcludeRulePresent || anyNonExcludeRuleSatisfied;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700266}
267
chrisweirbee3d2c2019-11-19 10:23:37 -0800268void CanBus::notifyErrorListeners(ErrorEvent err, bool isFatal) {
269 std::lock_guard<std::mutex> lck(mErrListenersGuard);
270 for (auto& listener : mErrListeners) {
271 if (!listener->onError(err, isFatal).isOk()) {
272 LOG(WARNING) << "Failed to notify listener about error";
273 }
274 }
275}
276
277static ErrorEvent parseErrorFrame(const struct canfd_frame& frame) {
278 // decode error frame (to a degree)
279 if ((frame.can_id & (CAN_ERR_BUSERROR | CAN_ERR_BUSOFF)) != 0) {
280 return ErrorEvent::BUS_ERROR;
281 }
282 if ((frame.data[1] & CAN_ERR_CRTL_TX_OVERFLOW) != 0) {
283 return ErrorEvent::TX_OVERFLOW;
284 }
285 if ((frame.data[1] & CAN_ERR_CRTL_RX_OVERFLOW) != 0) {
286 return ErrorEvent::RX_OVERFLOW;
287 }
288 if ((frame.data[2] & CAN_ERR_PROT_OVERLOAD) != 0) {
289 return ErrorEvent::BUS_OVERLOAD;
290 }
291 if ((frame.can_id & CAN_ERR_PROT) != 0) {
292 return ErrorEvent::MALFORMED_INPUT;
293 }
294 if ((frame.can_id & (CAN_ERR_CRTL | CAN_ERR_TRX | CAN_ERR_RESTARTED)) != 0) {
295 // "controller restarted" constitutes a HARDWARE_ERROR imo
296 return ErrorEvent::HARDWARE_ERROR;
297 }
298 return ErrorEvent::UNKNOWN_ERROR;
299}
300
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700301void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) {
chrisweirbee3d2c2019-11-19 10:23:37 -0800302 if ((frame.can_id & CAN_ERR_FLAG) != 0) {
303 // error bit is set
304 LOG(WARNING) << "CAN Error frame received";
305 // TODO(b/144458917) consider providing different values for isFatal, depending on error
306 notifyErrorListeners(parseErrorFrame(frame), false);
307 return;
308 }
309
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700310 CanMessage message = {};
chrisweirbee3d2c2019-11-19 10:23:37 -0800311 message.id = frame.can_id & CAN_EFF_MASK; // mask out eff/rtr/err flags
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700312 message.payload = hidl_vec<uint8_t>(frame.data, frame.data + frame.len);
313 message.timestamp = timestamp.count();
chrisweirbee3d2c2019-11-19 10:23:37 -0800314 message.isExtendedId = (frame.can_id & CAN_EFF_FLAG) != 0;
315 message.remoteTransmissionRequest = (frame.can_id & CAN_RTR_FLAG) != 0;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700316
317 if (UNLIKELY(kSuperVerbose)) {
318 LOG(VERBOSE) << "Got message " << toString(message);
319 }
320
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800321 std::lock_guard<std::mutex> lck(mMsgListenersGuard);
322 for (auto& listener : mMsgListeners) {
chrisweirbee3d2c2019-11-19 10:23:37 -0800323 if (!match(listener.filter, message.id, message.remoteTransmissionRequest,
324 message.isExtendedId))
325 continue;
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800326 if (!listener.callback->onReceive(message).isOk() && !listener.failedOnce) {
327 listener.failedOnce = true;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700328 LOG(WARNING) << "Failed to notify listener about message";
329 }
330 }
331}
332
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800333void CanBus::onError(int errnoVal) {
334 auto eventType = ErrorEvent::HARDWARE_ERROR;
335
336 if (errnoVal == ENODEV || errnoVal == ENETDOWN) {
337 mDownAfterUse = false;
338 eventType = ErrorEvent::INTERFACE_DOWN;
339 }
chrisweirbee3d2c2019-11-19 10:23:37 -0800340 notifyErrorListeners(eventType, true);
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800341
342 const auto errcb = mErrCb;
343 if (errcb != nullptr) errcb();
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700344}
345
Tomasz Wasilczyk55f21932019-12-20 09:20:24 -0800346} // namespace android::hardware::automotive::can::V1_0::implementation