blob: 65da291b0bb46e7c9153a562c8b8566517cb7228 [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
71 std::lock_guard<std::mutex> lckListeners(mListenersGuard);
72
73 sp<CloseHandle> closeHandle = new CloseHandle([this, listenerCb]() {
74 std::lock_guard<std::mutex> lck(mListenersGuard);
75 std::erase_if(mListeners, [&](const auto& e) { return e.callback == listenerCb; });
76 });
77 mListeners.emplace_back(CanMessageListener{listenerCb, filter, closeHandle});
78 auto& listener = mListeners.back();
79
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
94 std::lock_guard<std::mutex> lckListeners(mListenersGuard);
95 CHECK(mListeners.empty()) << "Listeners list is not empty while interface is being destroyed";
96}
97
98ICanController::Result CanBus::preUp() {
99 return ICanController::Result::OK;
100}
101
102bool CanBus::postDown() {
103 return true;
104}
105
106ICanController::Result CanBus::up() {
107 std::lock_guard<std::mutex> lck(mIsUpGuard);
108
109 if (mIsUp) {
110 LOG(WARNING) << "Interface is already up";
111 return ICanController::Result::INVALID_STATE;
112 }
113
114 const auto preResult = preUp();
115 if (preResult != ICanController::Result::OK) return preResult;
116
117 const auto isUp = netdevice::isUp(mIfname);
118 if (!isUp.has_value()) {
119 // preUp() should prepare the interface (either create or make sure it's there)
120 LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
121 return ICanController::Result::BAD_ADDRESS;
122 }
123 mWasUpInitially = *isUp;
124
125 if (!mWasUpInitially && !netdevice::up(mIfname)) {
126 LOG(ERROR) << "Can't bring " << mIfname << " up";
127 return ICanController::Result::UNKNOWN_ERROR;
128 }
129
130 using namespace std::placeholders;
131 CanSocket::ReadCallback rdcb = std::bind(&CanBus::onRead, this, _1, _2);
132 CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this);
133 mSocket = CanSocket::open(mIfname, rdcb, errcb);
134 if (!mSocket) {
135 if (!mWasUpInitially) netdevice::down(mIfname);
136 return ICanController::Result::UNKNOWN_ERROR;
137 }
138
139 mIsUp = true;
140 return ICanController::Result::OK;
141}
142
143void CanBus::clearListeners() {
144 std::vector<wp<ICloseHandle>> listenersToClose;
145 {
146 std::lock_guard<std::mutex> lck(mListenersGuard);
147 std::transform(mListeners.begin(), mListeners.end(), std::back_inserter(listenersToClose),
148 [](const auto& e) { return e.closeHandle; });
149 }
150
151 for (auto& weakListener : listenersToClose) {
152 /* Between populating listenersToClose and calling close method here, some listeners might
153 * have been already removed from the original mListeners list (resulting in a dangling weak
154 * pointer here). It's fine - we just want to clean them up. */
155 auto listener = weakListener.promote();
156 if (listener != nullptr) listener->close();
157 }
158
159 std::lock_guard<std::mutex> lck(mListenersGuard);
160 CHECK(mListeners.empty()) << "Listeners list wasn't emptied";
161}
162
163bool CanBus::down() {
164 std::lock_guard<std::mutex> lck(mIsUpGuard);
165
166 if (!mIsUp) {
167 LOG(WARNING) << "Interface is already down";
168 return false;
169 }
170 mIsUp = false;
171
172 clearListeners();
173 mSocket.reset();
174
175 bool success = true;
176
177 if (!mWasUpInitially && !netdevice::down(mIfname)) {
178 LOG(ERROR) << "Can't bring " << mIfname << " down";
179 // don't return yet, let's try to do best-effort cleanup
180 success = false;
181 }
182
183 if (!postDown()) success = false;
184
185 return success;
186}
187
188/**
189 * Match the filter set against message id.
190 *
191 * For details on the filters syntax, please see CanMessageFilter at
192 * the HAL definition (types.hal).
193 *
194 * \param filter Filter to match against
195 * \param id Message id to filter
196 * \return true if the message id matches the filter, false otherwise
197 */
198static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id) {
199 if (filter.size() == 0) return true;
200
201 bool anyNonInvertedPresent = false;
202 bool anyNonInvertedSatisfied = false;
203 for (auto& rule : filter) {
204 const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted;
205 if (rule.inverted) {
206 // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set.
207 if (!satisfied) return false;
208 } else {
209 anyNonInvertedPresent = true;
210 if (satisfied) anyNonInvertedSatisfied = true;
211 }
212 }
213 return !anyNonInvertedPresent || anyNonInvertedSatisfied;
214}
215
216void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) {
217 CanMessage message = {};
218 message.id = frame.can_id;
219 message.payload = hidl_vec<uint8_t>(frame.data, frame.data + frame.len);
220 message.timestamp = timestamp.count();
221
222 if (UNLIKELY(kSuperVerbose)) {
223 LOG(VERBOSE) << "Got message " << toString(message);
224 }
225
226 std::lock_guard<std::mutex> lck(mListenersGuard);
227 for (auto& listener : mListeners) {
228 if (!match(listener.filter, message.id)) continue;
229 if (!listener.callback->onReceive(message).isOk()) {
230 LOG(WARNING) << "Failed to notify listener about message";
231 }
232 }
233}
234
235void CanBus::onError() {
236 std::lock_guard<std::mutex> lck(mListenersGuard);
237 for (auto& listener : mListeners) {
238 if (!listener.callback->onError(ErrorEvent::HARDWARE_ERROR).isOk()) {
239 LOG(WARNING) << "Failed to notify listener about error";
240 }
241 }
242}
243
244} // namespace implementation
245} // namespace V1_0
246} // namespace can
247} // namespace automotive
248} // namespace hardware
249} // namespace android