blob: dd8040233e1a089bca357bc8b702d1f9deb7f1c1 [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
Tomasz Wasilczyk55f21932019-12-20 09:20:24 -080028namespace android::hardware::automotive::can::V1_0::implementation {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070029
Tomasz Wasilczykf3da9b62020-02-14 10:54:28 -080030using IfId = ICanController::BusConfig::InterfaceId;
31using IfIdDisc = ICanController::BusConfig::InterfaceId::hidl_discriminator;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070032
33Return<void> CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) {
chrisweircf36cea2019-11-08 16:41:02 -080034 _hidl_cb({ICanController::InterfaceType::VIRTUAL, ICanController::InterfaceType::SOCKETCAN,
35 ICanController::InterfaceType::SLCAN});
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070036 return {};
37}
38
39static bool isValidName(const std::string& name) {
40 static const std::regex nameRE("^[a-zA-Z0-9_]{1,32}$");
41 return std::regex_match(name, nameRE);
42}
43
Tomasz Wasilczykf3da9b62020-02-14 10:54:28 -080044Return<ICanController::Result> CanController::upInterface(const ICanController::BusConfig& config) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070045 LOG(VERBOSE) << "Attempting to bring interface up: " << toString(config);
46
47 std::lock_guard<std::mutex> lck(mCanBusesGuard);
48
49 if (!isValidName(config.name)) {
50 LOG(ERROR) << "Bus name " << config.name << " is invalid";
51 return ICanController::Result::UNKNOWN_ERROR;
52 }
53
54 if (mCanBuses.find(config.name) != mCanBuses.end()) {
55 LOG(ERROR) << "Bus " << config.name << " is already up";
56 return ICanController::Result::INVALID_STATE;
57 }
58
59 sp<CanBus> busService;
60
Tomasz Wasilczykf3da9b62020-02-14 10:54:28 -080061 if (config.interfaceId.getDiscriminator() == IfIdDisc::socketcan) {
62 // TODO(b/142654031): support serialno
63 auto& socketcan = config.interfaceId.socketcan();
64 if (socketcan.getDiscriminator() == IfId::Socketcan::hidl_discriminator::ifname) {
65 busService = new CanBusNative(socketcan.ifname(), config.bitrate);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070066 } else {
Tomasz Wasilczykf3da9b62020-02-14 10:54:28 -080067 return ICanController::Result::BAD_INTERFACE_ID;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070068 }
Tomasz Wasilczykf3da9b62020-02-14 10:54:28 -080069 } else if (config.interfaceId.getDiscriminator() == IfIdDisc::virtualif) {
70 busService = new CanBusVirtual(config.interfaceId.virtualif().ifname);
71 } else if (config.interfaceId.getDiscriminator() == IfIdDisc::slcan) {
72 // TODO(b/142654031): support serialno
73 auto& slcan = config.interfaceId.slcan();
74 if (slcan.getDiscriminator() == IfId::Slcan::hidl_discriminator::ttyname) {
75 busService = new CanBusSlcan(slcan.ttyname(), config.bitrate);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070076 } else {
Tomasz Wasilczykf3da9b62020-02-14 10:54:28 -080077 return ICanController::Result::BAD_INTERFACE_ID;
chrisweircf36cea2019-11-08 16:41:02 -080078 }
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070079 } else {
80 return ICanController::Result::NOT_SUPPORTED;
81 }
82
Tomasz Wasilczyka9061962019-11-04 12:53:09 -080083 busService->setErrorCallback([this, name = config.name]() { downInterface(name); });
84
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070085 const auto result = busService->up();
86 if (result != ICanController::Result::OK) return result;
87
88 if (busService->registerAsService(config.name) != OK) {
89 LOG(ERROR) << "Failed to register ICanBus/" << config.name;
90 if (!busService->down()) {
91 LOG(WARNING) << "Failed to bring down CAN bus that failed to register";
92 }
93 return ICanController::Result::UNKNOWN_ERROR;
94 }
95
96 mCanBuses[config.name] = busService;
97
98 return ICanController::Result::OK;
99}
100
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800101static bool unregisterCanBusService(const hidl_string& name, sp<CanBus> busService) {
102 auto manager = hidl::manager::V1_2::IServiceManager::getService();
103 if (!manager) return false;
104 const auto res = manager->tryUnregister(ICanBus::descriptor, name, busService);
105 if (!res.isOk()) return false;
106 return res;
107}
108
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700109Return<bool> CanController::downInterface(const hidl_string& name) {
110 LOG(VERBOSE) << "Attempting to bring interface down: " << name;
111
112 std::lock_guard<std::mutex> lck(mCanBusesGuard);
113
114 auto busEntry = mCanBuses.extract(name);
115 if (!busEntry) {
116 LOG(WARNING) << "Interface " << name << " is not up";
117 return false;
118 }
119
120 auto success = true;
121
Tomasz Wasilczyka9061962019-11-04 12:53:09 -0800122 if (!unregisterCanBusService(name, busEntry.mapped())) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700123 LOG(ERROR) << "Couldn't unregister " << name;
124 // don't return yet, let's try to do best-effort cleanup
125 success = false;
126 }
127
128 if (!busEntry.mapped()->down()) {
129 LOG(ERROR) << "Couldn't bring " << name << " down";
130 success = false;
131 }
132
133 return success;
134}
135
Tomasz Wasilczyk55f21932019-12-20 09:20:24 -0800136} // namespace android::hardware::automotive::can::V1_0::implementation