/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "CanClient.h" #include #include #include #include namespace android { namespace hardware { namespace automotive { namespace can { namespace V1_0 { namespace utils { using hidl::manager::V1_1::IServiceManager; using hidl::manager::V1_0::IServiceNotification; CanClient::CanClient(const std::string& busName) : mBusName(busName) {} ::ndk::ScopedAStatus CanClient::start() { VehicleBus::start(); LOG(VERBOSE) << "Waiting for ICanBus/" << mBusName; ICanBus::registerForNotifications(mBusName, static_cast(this)); return ::ndk::ScopedAStatus::ok(); } CanClient::~CanClient() { auto manager = IServiceManager::getService(); CHECK(manager != nullptr) << "Can't fetch IServiceManager"; manager->unregisterForNotifications("", "", static_cast(this)); close(); } void CanClient::onReady(const sp&) {} Return CanClient::onRegistration(const hidl_string&, const hidl_string& name, bool) { LOG(VERBOSE) << "ICanBus/" << name << " is registered"; auto bus = ICanBus::tryGetService(name); if (bus == nullptr) { LOG(WARNING) << "Can't fetch ICanBus/" << name; return {}; } std::lock_guard lck(mCanBusGuard); if (mCanBus) { LOG(DEBUG) << "Bus " << mBusName << " service is already registered"; return {}; } mCanBus = bus; // TODO(b/146214370): configure CAN message filtering (see first argument to listen()) Result halResult; sp listenerCloseHandle; // TODO(b/146214370): check why the cast requires transfer SEPolicy permission auto res = bus->listen({}, static_cast(this), hidl_utils::fill(&halResult, &listenerCloseHandle)); mListenerCloseHandle = CloseHandleWrapper(listenerCloseHandle); if (!res.isOk() || halResult != Result::OK) { LOG(WARNING) << "Listen call failed"; close(); return {}; } auto errRes = bus->listenForErrors(static_cast(this)); if (!errRes.isOk()) { LOG(WARNING) << "listenForErrors call failed"; close(); return {}; } mErrorCloseHandle = CloseHandleWrapper(errRes); if (!bus->linkToDeath(static_cast(this), 0).withDefault(false)) { LOG(WARNING) << "linkToDeath failed"; close(); return {}; } LOG(INFO) << "Bus " << mBusName << " successfully configured"; onReady(mCanBus); return {}; } void CanClient::serviceDied(uint64_t, const wp&) { onError(ErrorEvent::INTERFACE_DOWN, true); } Return CanClient::onError(ErrorEvent error, bool isFatal) { if (!isFatal) { LOG(VERBOSE) << "Got non-fatal error from CAN bus HAL: " << toString(error); return {}; } LOG(DEBUG) << "Got fatal error from CAN bus HAL: " << toString(error); if (!close()) { LOG(WARNING) << "Service is dead already"; return {}; } LOG(INFO) << "Bus " << mBusName << " became unavailable, waiting for it to come back..."; return {}; } bool CanClient::close() { std::lock_guard lck(mCanBusGuard); mListenerCloseHandle.close(); mErrorCloseHandle.close(); if (mCanBus == nullptr) return false; if (!mCanBus->unlinkToDeath(static_cast(this)).isOk()) { LOG(WARNING) << "unlinkToDeath failed"; } mCanBus = nullptr; return true; } } // namespace utils } // namespace V1_0 } // namespace can } // namespace automotive } // namespace hardware } // namespace android