blob: ffdc9125fc5b256624c4a44953f7c63a4a8d8faf [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 "CanController.h"
18
19#include "CanBusNative.h"
chrisweircf36cea2019-11-08 16:41:02 -080020#include "CanBusSlcan.h"
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070021#include "CanBusVirtual.h"
22
23#include <android-base/logging.h>
24#include <android/hidl/manager/1.2/IServiceManager.h>
25
26#include <regex>
27
28namespace android {
29namespace hardware {
30namespace automotive {
31namespace can {
32namespace V1_0 {
33namespace implementation {
34
35using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
36
37Return<void> CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) {
chrisweircf36cea2019-11-08 16:41:02 -080038 _hidl_cb({ICanController::InterfaceType::VIRTUAL, ICanController::InterfaceType::SOCKETCAN,
39 ICanController::InterfaceType::SLCAN});
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070040 return {};
41}
42
43static bool isValidName(const std::string& name) {
44 static const std::regex nameRE("^[a-zA-Z0-9_]{1,32}$");
45 return std::regex_match(name, nameRE);
46}
47
48Return<ICanController::Result> CanController::upInterface(
49 const ICanController::BusConfiguration& config) {
50 LOG(VERBOSE) << "Attempting to bring interface up: " << toString(config);
51
52 std::lock_guard<std::mutex> lck(mCanBusesGuard);
53
54 if (!isValidName(config.name)) {
55 LOG(ERROR) << "Bus name " << config.name << " is invalid";
56 return ICanController::Result::UNKNOWN_ERROR;
57 }
58
59 if (mCanBuses.find(config.name) != mCanBuses.end()) {
60 LOG(ERROR) << "Bus " << config.name << " is already up";
61 return ICanController::Result::INVALID_STATE;
62 }
63
64 sp<CanBus> busService;
65
66 if (config.iftype == ICanController::InterfaceType::SOCKETCAN) {
67 // TODO(b/135918744): support serialno
68 if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
69 busService = new CanBusNative(config.interfaceId.address(), config.baudrate);
70 } else {
71 return ICanController::Result::BAD_ADDRESS;
72 }
73 } else if (config.iftype == ICanController::InterfaceType::VIRTUAL) {
74 if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
75 busService = new CanBusVirtual(config.interfaceId.address());
76 } else {
77 return ICanController::Result::BAD_ADDRESS;
78 }
chrisweircf36cea2019-11-08 16:41:02 -080079 } else if (config.iftype == ICanController::InterfaceType::SLCAN) {
80 if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
81 busService = new CanBusSlcan(config.interfaceId.address(), config.baudrate);
82 } else {
83 return ICanController::Result::BAD_ADDRESS;
84 }
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070085 } else {
86 return ICanController::Result::NOT_SUPPORTED;
87 }
88
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080089 busService->setErrorCallback([this, name = config.name]() { downInterface(name); });
90
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070091 const auto result = busService->up();
92 if (result != ICanController::Result::OK) return result;
93
94 if (busService->registerAsService(config.name) != OK) {
95 LOG(ERROR) << "Failed to register ICanBus/" << config.name;
96 if (!busService->down()) {
97 LOG(WARNING) << "Failed to bring down CAN bus that failed to register";
98 }
99 return ICanController::Result::UNKNOWN_ERROR;
100 }
101
102 mCanBuses[config.name] = busService;
103
104 return ICanController::Result::OK;
105}
106
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800107static bool unregisterCanBusService(const hidl_string& name, sp<CanBus> busService) {
108 auto manager = hidl::manager::V1_2::IServiceManager::getService();
109 if (!manager) return false;
110 const auto res = manager->tryUnregister(ICanBus::descriptor, name, busService);
111 if (!res.isOk()) return false;
112 return res;
113}
114
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700115Return<bool> CanController::downInterface(const hidl_string& name) {
116 LOG(VERBOSE) << "Attempting to bring interface down: " << name;
117
118 std::lock_guard<std::mutex> lck(mCanBusesGuard);
119
120 auto busEntry = mCanBuses.extract(name);
121 if (!busEntry) {
122 LOG(WARNING) << "Interface " << name << " is not up";
123 return false;
124 }
125
126 auto success = true;
127
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800128 if (!unregisterCanBusService(name, busEntry.mapped())) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700129 LOG(ERROR) << "Couldn't unregister " << name;
130 // don't return yet, let's try to do best-effort cleanup
131 success = false;
132 }
133
134 if (!busEntry.mapped()->down()) {
135 LOG(ERROR) << "Couldn't bring " << name << " down";
136 success = false;
137 }
138
139 return success;
140}
141
142} // namespace implementation
143} // namespace V1_0
144} // namespace can
145} // namespace automotive
146} // namespace hardware
147} // namespace android