1 /*
2  * Copyright (C) 2022 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 "thread_chip.hpp"
18 
19 #include <android-base/logging.h>
20 #include <android/binder_auto_utils.h>
21 #include <android/binder_ibinder.h>
22 #include <android/binder_manager.h>
23 #include <android/binder_process.h>
24 #include <utils/Log.h>
25 
26 #include "hdlc_interface.hpp"
27 #include "socket_interface.hpp"
28 #include "spi_interface.hpp"
29 
30 namespace aidl {
31 namespace android {
32 namespace hardware {
33 namespace threadnetwork {
34 
ThreadChip(const char * url)35 ThreadChip::ThreadChip(const char* url) : mUrl(url), mRxFrameBuffer(), mCallback(nullptr) {
36     const char* interfaceName;
37 
38     interfaceName = mUrl.GetProtocol();
39     CHECK_NE(interfaceName, nullptr);
40 
41     if (ot::Posix::SpiInterface::IsInterfaceNameMatch(interfaceName)) {
42         mSpinelInterface = std::make_shared<ot::Posix::SpiInterface>(mUrl);
43     } else if (ot::Posix::HdlcInterface::IsInterfaceNameMatch(interfaceName)) {
44         mSpinelInterface = std::make_shared<ot::Posix::HdlcInterface>(mUrl);
45     } else if (SocketInterface::IsInterfaceNameMatch(interfaceName)) {
46         mSpinelInterface = std::make_shared<SocketInterface>(mUrl);
47     } else {
48         ALOGE("The interface \"%s\" is not supported", interfaceName);
49         exit(EXIT_FAILURE);
50     }
51 
52     CHECK_NE(mSpinelInterface, nullptr);
53 
54     mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
55             AIBinder_DeathRecipient_new(ThreadChip::onBinderDiedJump));
56     AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinkedJump);
57 }
58 
onBinderDiedJump(void * context)59 void ThreadChip::onBinderDiedJump(void* context) {
60     reinterpret_cast<ThreadChip*>(context)->onBinderDied();
61 }
62 
onBinderDied(void)63 void ThreadChip::onBinderDied(void) {
64     ALOGW("Thread Network HAL client is dead");
65 }
66 
onBinderUnlinkedJump(void * context)67 void ThreadChip::onBinderUnlinkedJump(void* context) {
68     reinterpret_cast<ThreadChip*>(context)->onBinderUnlinked();
69 }
70 
onBinderUnlinked(void)71 void ThreadChip::onBinderUnlinked(void) {
72     ALOGW("ThreadChip binder is unlinked");
73     deinitChip();
74 }
75 
handleReceivedFrameJump(void * context)76 void ThreadChip::handleReceivedFrameJump(void* context) {
77     static_cast<ThreadChip*>(context)->handleReceivedFrame();
78 }
79 
handleReceivedFrame(void)80 void ThreadChip::handleReceivedFrame(void) {
81     if (mCallback != nullptr) {
82         mCallback->onReceiveSpinelFrame(std::vector<uint8_t>(
83                 mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetFrame() + mRxFrameBuffer.GetLength()));
84     }
85 
86     mRxFrameBuffer.DiscardFrame();
87 }
88 
open(const std::shared_ptr<IThreadChipCallback> & in_callback)89 ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr<IThreadChipCallback>& in_callback) {
90     ndk::ScopedAStatus status = initChip(in_callback);
91 
92     if (status.isOk()) {
93         AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this);
94         ALOGI("Open IThreadChip successfully");
95     } else {
96         ALOGW("Failed to open IThreadChip: %s", status.getDescription().c_str());
97     }
98 
99     return status;
100 }
101 
initChip(const std::shared_ptr<IThreadChipCallback> & in_callback)102 ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr<IThreadChipCallback>& in_callback) {
103     if (in_callback == nullptr) {
104         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
105     } else if (mCallback == nullptr) {
106         if (mSpinelInterface->Init(handleReceivedFrameJump, this, mRxFrameBuffer) !=
107             OT_ERROR_NONE) {
108             return errorStatus(ERROR_FAILED, "Failed to initialize the interface");
109         }
110 
111         mCallback = in_callback;
112         ot::Posix::Mainloop::Manager::Get().Add(*this);
113         return ndk::ScopedAStatus::ok();
114     } else {
115         return errorStatus(ERROR_BUSY, "Interface has been opened");
116     }
117 }
118 
close()119 ndk::ScopedAStatus ThreadChip::close() {
120     ndk::ScopedAStatus status;
121     std::shared_ptr<IThreadChipCallback> callback = mCallback;
122 
123     status = deinitChip();
124     if (status.isOk()) {
125         if (callback != nullptr) {
126             AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this);
127         }
128 
129         ALOGI("Close IThreadChip successfully");
130     } else {
131         ALOGW("Failed to close IThreadChip: %s", status.getDescription().c_str());
132     }
133 
134     return status;
135 }
136 
deinitChip()137 ndk::ScopedAStatus ThreadChip::deinitChip() {
138     if (mCallback != nullptr) {
139         mSpinelInterface->Deinit();
140         ot::Posix::Mainloop::Manager::Get().Remove(*this);
141         mCallback = nullptr;
142         return ndk::ScopedAStatus::ok();
143     }
144 
145     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
146 }
147 
sendSpinelFrame(const std::vector<uint8_t> & in_frame)148 ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector<uint8_t>& in_frame) {
149     ndk::ScopedAStatus status;
150     otError error;
151 
152     if (mCallback == nullptr) {
153         status = errorStatus(ERROR_FAILED, "The interface is not open");
154     } else {
155         error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
156                                             in_frame.size());
157         if (error == OT_ERROR_NONE) {
158             status = ndk::ScopedAStatus::ok();
159         } else if (error == OT_ERROR_NO_BUFS) {
160             status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
161         } else if (error == OT_ERROR_BUSY) {
162             status = errorStatus(ERROR_BUSY, "The interface is busy");
163         } else {
164             status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
165         }
166     }
167 
168     if (!status.isOk()) {
169         ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str());
170     }
171 
172     return status;
173 }
174 
hardwareReset()175 ndk::ScopedAStatus ThreadChip::hardwareReset() {
176     if (mSpinelInterface->HardwareReset() == OT_ERROR_NOT_IMPLEMENTED) {
177         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
178     }
179 
180     ALOGI("reset()");
181     return ndk::ScopedAStatus::ok();
182 }
183 
Update(otSysMainloopContext & context)184 void ThreadChip::Update(otSysMainloopContext& context) {
185     if (mCallback != nullptr) {
186         mSpinelInterface->UpdateFdSet(&context);
187     }
188 }
189 
Process(const otSysMainloopContext & context)190 void ThreadChip::Process(const otSysMainloopContext& context) {
191     if (mCallback != nullptr) {
192         mSpinelInterface->Process(&context);
193     }
194 }
195 
errorStatus(int32_t error,const char * message)196 ndk::ScopedAStatus ThreadChip::errorStatus(int32_t error, const char* message) {
197     return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(error, message));
198 }
199 }  // namespace threadnetwork
200 }  // namespace hardware
201 }  // namespace android
202 }  // namespace aidl
203