1 /*
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 "CanClient.h"
18
19 #include <android-base/logging.h>
20 #include <android/hardware/automotive/can/1.0/ICanMessageListener.h>
21 #include <android/hidl/manager/1.1/IServiceManager.h>
22 #include <hidl-utils/hidl-utils.h>
23
24 namespace android {
25 namespace hardware {
26 namespace automotive {
27 namespace can {
28 namespace V1_0 {
29 namespace utils {
30
31 using hidl::manager::V1_1::IServiceManager;
32 using hidl::manager::V1_0::IServiceNotification;
33
CanClient(const std::string & busName)34 CanClient::CanClient(const std::string& busName) : mBusName(busName) {}
35
start()36 ::ndk::ScopedAStatus CanClient::start() {
37 VehicleBus::start();
38 LOG(VERBOSE) << "Waiting for ICanBus/" << mBusName;
39 ICanBus::registerForNotifications(mBusName, static_cast<IServiceNotification*>(this));
40 return ::ndk::ScopedAStatus::ok();
41 }
42
~CanClient()43 CanClient::~CanClient() {
44 auto manager = IServiceManager::getService();
45 CHECK(manager != nullptr) << "Can't fetch IServiceManager";
46 manager->unregisterForNotifications("", "", static_cast<IServiceNotification*>(this));
47
48 close();
49 }
50
onReady(const sp<ICanBus> &)51 void CanClient::onReady(const sp<ICanBus>&) {}
52
onRegistration(const hidl_string &,const hidl_string & name,bool)53 Return<void> CanClient::onRegistration(const hidl_string&, const hidl_string& name, bool) {
54 LOG(VERBOSE) << "ICanBus/" << name << " is registered";
55 auto bus = ICanBus::tryGetService(name);
56 if (bus == nullptr) {
57 LOG(WARNING) << "Can't fetch ICanBus/" << name;
58 return {};
59 }
60
61 std::lock_guard<std::mutex> lck(mCanBusGuard);
62 if (mCanBus) {
63 LOG(DEBUG) << "Bus " << mBusName << " service is already registered";
64 return {};
65 }
66 mCanBus = bus;
67
68 // TODO(b/146214370): configure CAN message filtering (see first argument to listen())
69 Result halResult;
70 sp<ICloseHandle> listenerCloseHandle;
71 // TODO(b/146214370): check why the cast requires transfer SEPolicy permission
72 auto res = bus->listen({}, static_cast<ICanMessageListener*>(this),
73 hidl_utils::fill(&halResult, &listenerCloseHandle));
74 mListenerCloseHandle = CloseHandleWrapper(listenerCloseHandle);
75 if (!res.isOk() || halResult != Result::OK) {
76 LOG(WARNING) << "Listen call failed";
77 close();
78 return {};
79 }
80
81 auto errRes = bus->listenForErrors(static_cast<ICanErrorListener*>(this));
82 if (!errRes.isOk()) {
83 LOG(WARNING) << "listenForErrors call failed";
84 close();
85 return {};
86 }
87 mErrorCloseHandle = CloseHandleWrapper(errRes);
88
89 if (!bus->linkToDeath(static_cast<hidl_death_recipient*>(this), 0).withDefault(false)) {
90 LOG(WARNING) << "linkToDeath failed";
91 close();
92 return {};
93 }
94
95 LOG(INFO) << "Bus " << mBusName << " successfully configured";
96 onReady(mCanBus);
97 return {};
98 }
99
serviceDied(uint64_t,const wp<hidl::base::V1_0::IBase> &)100 void CanClient::serviceDied(uint64_t, const wp<hidl::base::V1_0::IBase>&) {
101 onError(ErrorEvent::INTERFACE_DOWN, true);
102 }
103
onError(ErrorEvent error,bool isFatal)104 Return<void> CanClient::onError(ErrorEvent error, bool isFatal) {
105 if (!isFatal) {
106 LOG(VERBOSE) << "Got non-fatal error from CAN bus HAL: " << toString(error);
107 return {};
108 }
109
110 LOG(DEBUG) << "Got fatal error from CAN bus HAL: " << toString(error);
111
112 if (!close()) {
113 LOG(WARNING) << "Service is dead already";
114 return {};
115 }
116 LOG(INFO) << "Bus " << mBusName << " became unavailable, waiting for it to come back...";
117
118 return {};
119 }
120
close()121 bool CanClient::close() {
122 std::lock_guard<std::mutex> lck(mCanBusGuard);
123 mListenerCloseHandle.close();
124 mErrorCloseHandle.close();
125 if (mCanBus == nullptr) return false;
126 if (!mCanBus->unlinkToDeath(static_cast<hidl_death_recipient*>(this)).isOk()) {
127 LOG(WARNING) << "unlinkToDeath failed";
128 }
129 mCanBus = nullptr;
130 return true;
131 }
132
133 } // namespace utils
134 } // namespace V1_0
135 } // namespace can
136 } // namespace automotive
137 } // namespace hardware
138 } // namespace android
139