• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "daemon_uart.h"
16 
17 #include <thread>
18 #include <fcntl.h>
19 #include <file_ex.h>
20 #include <string_ex.h>
21 
22 #include <sys/file.h>
23 #include <sys/mount.h>
24 #include <sys/select.h>
25 #include <sys/time.h>
26 
27 namespace Hdc {
HdcDaemonUART(HdcDaemon & daemonSessionIn,ExternInterface & externInterface)28 HdcDaemonUART::HdcDaemonUART(HdcDaemon &daemonSessionIn, ExternInterface &externInterface)
29     : HdcUARTBase(daemonSessionIn, externInterface), daemon(daemonSessionIn)
30 {
31     checkSerialPort.data = nullptr;
32 }
33 
Initial(const std::string & devPathIn)34 int HdcDaemonUART::Initial(const std::string &devPathIn)
35 {
36     int ret = 0;
37     devPath = devPathIn;
38     WRITE_LOG(LOG_DEBUG, "HdcDaemonUART init");
39     if (access(devPath.c_str(), F_OK) != 0) {
40         WRITE_LOG(LOG_DEBUG, "uartMod Disable");
41         return -1;
42     }
43 #ifndef HDC_UT
44     std::string consoleActive;
45     if (OHOS::LoadStringFromFile(CONSOLE_ACTIVE_NODE, consoleActive)) {
46         consoleActive = OHOS::TrimStr(consoleActive,'\n');
47         WRITE_LOG(LOG_DEBUG, "consoleActive (%d):%s", consoleActive.length(),
48                   consoleActive.c_str());
49         if (devPathIn.find(consoleActive.c_str()) != std::string::npos) {
50             WRITE_LOG(LOG_FATAL,
51                       "kernel use this dev(%s) as console , we can't open it as hdc uart dev",
52                       devPathIn.c_str());
53             return -1;
54         }
55     }
56 #endif
57     constexpr int bufSize = 1024;
58     char buf[bufSize] = { 0 };
59     const uint16_t uartScanInterval = 1500;
60     ret = uv_timer_init(&daemon.loopMain, &checkSerialPort);
61     if (ret != 0) {
62         uv_err_name_r(ret, buf, bufSize);
63         WRITE_LOG(LOG_FATAL, "uv_timer_init failed %s", buf);
64     } else {
65         checkSerialPort.data = this;
66         ret = uv_timer_start(&checkSerialPort, UvWatchTimer, 0, uartScanInterval);
67         if (ret != 0) {
68             uv_err_name_r(ret, buf, bufSize);
69             WRITE_LOG(LOG_FATAL, "uv_timer_start failed %s", buf);
70         } else {
71             return 0;
72         }
73     }
74     return -1;
75 }
76 
PrepareBufForRead()77 int HdcDaemonUART::PrepareBufForRead()
78 {
79     constexpr int bufCoefficient = 1;
80     int readMax = MAX_UART_SIZE_IOBUF * bufCoefficient;
81     dataReadBuf.clear();
82     dataReadBuf.reserve(readMax);
83     return RET_SUCCESS;
84 }
85 
WatcherTimerCallBack()86 void HdcDaemonUART::WatcherTimerCallBack()
87 {
88     // try reanbel the uart device (reopen)
89     if (isAlive) {
90         return;
91     }
92     do {
93         if (uartHandle >= 0) {
94             if (CloseUartDevice() != RET_SUCCESS) {
95                 break;
96             }
97         }
98         if ((OpenUartDevice() != RET_SUCCESS)) {
99             WRITE_LOG(LOG_DEBUG, "OpenUartdevice fail ! ");
100             break;
101         }
102         if ((PrepareBufForRead() != RET_SUCCESS)) {
103             WRITE_LOG(LOG_DEBUG, "PrepareBufForRead fail ! ");
104             break;
105         }
106         // read and write thread need this flag
107         isAlive = true;
108         if ((LoopUARTRead() != RET_SUCCESS)) {
109             WRITE_LOG(LOG_DEBUG, "LoopUARTRead fail ! ");
110             break;
111         }
112         if ((LoopUARTWrite() != RET_SUCCESS)) {
113             WRITE_LOG(LOG_DEBUG, "LoopUARTWrite fail ! ");
114             break;
115         }
116         return;
117     } while (false);
118     WRITE_LOG(LOG_FATAL, "WatcherTimerCallBack found some issue");
119     isAlive = false;
120 }
121 
CloseUartDevice()122 int HdcDaemonUART::CloseUartDevice()
123 {
124     int ret = close(uartHandle);
125     if (ret < 0) {
126         constexpr int bufSize = 1024;
127         char buf[bufSize] = { 0 };
128         strerror_r(errno, buf, bufSize);
129         WRITE_LOG(LOG_FATAL, "DaemonUART stop for CloseBulkSpErrno: %d:%s\n", errno, buf);
130     } else {
131         uartHandle = -1;
132     }
133     isAlive = false;
134     return ret;
135 }
136 
OpenUartDevice()137 int HdcDaemonUART::OpenUartDevice()
138 {
139     int ret = ERR_GENERIC;
140     while (true) {
141         if ((uartHandle = open(devPath.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) < 0) {
142             WRITE_LOG(LOG_WARN, "%s: cannot open uartHandle: errno=%d", devPath.c_str(), errno);
143             break;
144         }
145         uv_sleep(uartIOWaitTime100);
146         // cannot open with O_CLOEXEC, must fcntl
147         fcntl(uartHandle, F_SETFD, FD_CLOEXEC);
148         int flag = fcntl(uartHandle, F_GETFL);
149         flag &= ~O_NONBLOCK;
150         fcntl(uartHandle, F_SETFL, flag);
151         WRITE_LOG(LOG_DEBUG, "Set SetSerial ");
152         if (SetSerial(uartHandle, DEFAULT_BAUD_RATE_VALUE, UART_BIT2, 'N', 1) != RET_SUCCESS) {
153             break;
154         }
155         ret = RET_SUCCESS;
156         break;
157     }
158     if (ret != RET_SUCCESS) {
159         WRITE_LOG(LOG_DEBUG, "OpenUartdevice SerialHandle:%d fail.", uartHandle);
160     }
161     return ret;
162 }
163 
ResetOldSession(uint32_t sessionId)164 void HdcDaemonUART::ResetOldSession(uint32_t sessionId)
165 {
166     if (sessionId == 0) {
167         sessionId = currentSessionId;
168     }
169     HSession hSession = daemon.AdminSession(OP_QUERY, sessionId, nullptr);
170     if (hSession == nullptr) {
171         return;
172     }
173     if (hSession->hUART != nullptr) {
174         hSession->hUART->resetIO = true;
175     }
176     // The Host side is restarted, but the USB cable is still connected
177     WRITE_LOG(LOG_WARN, "Hostside softreset to restart daemon, old sessionId:%u", sessionId);
178     OnTransferError(hSession);
179 }
180 
GetSession(const uint32_t sessionId,bool create=false)181 HSession HdcDaemonUART::GetSession(const uint32_t sessionId, bool create = false)
182 {
183     HSession hSession = daemon.AdminSession(OP_QUERY, sessionId, nullptr);
184     if (hSession == nullptr and create) {
185         hSession = PrepareNewSession(sessionId);
186     }
187     return hSession;
188 }
189 
OnTransferError(const HSession session)190 void HdcDaemonUART::OnTransferError(const HSession session)
191 {
192     // review maybe we can do something more ?
193     if (session != nullptr) {
194         WRITE_LOG(LOG_FATAL, "%s %s", __FUNCTION__, session->ToDebugString().c_str());
195         daemon.FreeSession(session->sessionId);
196         ClearUARTOutMap(session->sessionId);
197     }
198 }
199 
OnNewHandshakeOK(const uint32_t sessionId)200 void HdcDaemonUART::OnNewHandshakeOK(const uint32_t sessionId)
201 {
202     currentSessionId = sessionId;
203 }
204 
PrepareNewSession(uint32_t sessionId)205 HSession HdcDaemonUART::PrepareNewSession(uint32_t sessionId)
206 {
207     WRITE_LOG(LOG_FATAL, "%s sessionId:%u", __FUNCTION__, sessionId);
208     HSession hSession = daemon.MallocSession(false, CONN_SERIAL, this, sessionId);
209     if (!hSession) {
210         WRITE_LOG(LOG_FATAL, "new session malloc failed for sessionId:%u", sessionId);
211         return nullptr;
212     }
213     if (currentSessionId != 0) {
214         // reset old session
215         // The Host side is restarted, but the cable is still connected
216         WRITE_LOG(LOG_WARN, "New session coming, restart old sessionId:%u", currentSessionId);
217         daemon.PushAsyncMessage(currentSessionId, ASYNC_FREE_SESSION, nullptr, 0);
218     }
219     externInterface.StartWorkThread(&daemon.loopMain, daemon.SessionWorkThread,
220                                     Base::FinishWorkThread, hSession);
221     auto funcNewSessionUp = [](uv_timer_t *handle) -> void {
222         HSession hSession = reinterpret_cast<HSession>(handle->data);
223         HdcDaemon &daemonSession = *reinterpret_cast<HdcDaemon *>(hSession->classInstance);
224         if (hSession->childLoop.active_handles == 0) {
225             WRITE_LOG(LOG_DEBUG, "No active_handles.");
226             return;
227         }
228         if (!hSession->isDead) {
229             auto ctrl = daemonSession.BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
230             Base::SendToStream((uv_stream_t *)&hSession->ctrlPipe[STREAM_MAIN], ctrl.data(),
231                                ctrl.size());
232             WRITE_LOG(LOG_DEBUG, "Main thread uartio mirgate finish");
233         }
234         Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(handle), Base::CloseTimerCallback);
235     };
236     externInterface.TimerUvTask(&daemon.loopMain, hSession, funcNewSessionUp);
237     return hSession;
238 }
239 
240 // review Merge this with Host side
DeamonReadThread()241 void HdcDaemonUART::DeamonReadThread()
242 {
243     HdcUART deamonUart;
244     deamonUart.devUartHandle = uartHandle;
245     dataReadBuf.clear();
246     // after we got the head or something , we will expected some size
247     size_t expectedSize = 0;
248     // use < not <= because if it full , should not read again
249     while (isAlive && dataReadBuf.size() < MAX_READ_BUFFER) {
250         ssize_t bytesRead = ReadUartDev(dataReadBuf, expectedSize, deamonUart);
251         if (bytesRead == 0) {
252             WRITE_LOG(LOG_DEBUG, "%s read %zd, clean the data try read again.", __FUNCTION__,
253                       bytesRead);
254             // drop current cache
255             expectedSize = 0;
256             dataReadBuf.clear();
257             continue;
258         } else if (bytesRead < 0) {
259             WRITE_LOG(LOG_DEBUG, "%s read abnormal, stop uart module.", __FUNCTION__);
260             Stop();
261             break;
262         }
263         WRITE_LOG(LOG_DEBUG, "DeamonReadThread bytesRead:%d, totalReadBytes.size():%d.", bytesRead,
264                   dataReadBuf.size());
265 
266         if (dataReadBuf.size() < sizeof(UartHead)) {
267             continue; // no enough ,read again
268         }
269         expectedSize = PackageProcess(dataReadBuf);
270     }
271     if (isAlive) {
272         WRITE_LOG(LOG_WARN, "totalReadSize is full %zu/%zu, DeamonReadThread exit..",
273                   dataReadBuf.size(), expectedSize);
274     } else {
275         WRITE_LOG(LOG_WARN, "dev is not alive, DeamonReadThread exit..");
276     }
277     // why not free session here
278     isAlive = false;
279     return;
280 }
281 
DeamonWriteThread()282 void HdcDaemonUART::DeamonWriteThread()
283 {
284     while (isAlive) {
285         WRITE_LOG(LOG_DEBUG, "DeamonWriteThread wait sendLock.");
286         transfer.Wait();
287         SendPkgInUARTOutMap();
288     }
289     WRITE_LOG(LOG_WARN, "dev is not alive, DeamonWriteThread exit..");
290     return;
291 }
292 
LoopUARTRead()293 int HdcDaemonUART::LoopUARTRead()
294 {
295     try {
296         std::thread deamonReadThread(std::bind(&HdcDaemonUART::DeamonReadThread, this));
297         deamonReadThread.detach();
298         return 0;
299     } catch (...) {
300         WRITE_LOG(LOG_WARN, "create thread DeamonReadThread failed");
301     }
302     return -1;
303 }
304 
LoopUARTWrite()305 int HdcDaemonUART::LoopUARTWrite()
306 {
307     try {
308         std::thread deamonWriteThread(std::bind(&HdcDaemonUART::DeamonWriteThread, this));
309         deamonWriteThread.detach();
310         return 0;
311     } catch (...) {
312         WRITE_LOG(LOG_WARN, "create thread DeamonWriteThread failed");
313     }
314     return -1;
315 }
316 
IsSendReady(HSession hSession)317 bool HdcDaemonUART::IsSendReady(HSession hSession)
318 {
319     if (isAlive and !hSession->isDead and uartHandle >= 0 and !hSession->hUART->resetIO) {
320         return true;
321     } else {
322         if (!isAlive) {
323             WRITE_LOG(LOG_WARN, "!isAlive");
324         } else if (hSession->isDead) {
325             WRITE_LOG(LOG_WARN, "session isDead");
326         } else if (uartHandle < 0) {
327             WRITE_LOG(LOG_WARN, "uartHandle is not valid");
328         } else if (hSession->hUART->resetIO) {
329             WRITE_LOG(LOG_WARN, "session have resetIO");
330         }
331         return false;
332     }
333 };
334 
~HdcDaemonUART()335 HdcDaemonUART::~HdcDaemonUART()
336 {
337     Stop();
338 }
339 
Stop()340 void HdcDaemonUART::Stop()
341 {
342     WRITE_LOG(LOG_DEBUG, "%s run!", __FUNCTION__);
343     if (!stopped) {
344         stopped = true;
345         std::lock_guard<std::mutex> lock(workThreadProcessingData);
346 
347         // maybe some data response not back to host
348         // like smode need response.
349         ResponseUartTrans(currentSessionId, 0, PKG_OPTION_FREE);
350         EnsureAllPkgsSent();
351         isAlive = false;
352         WRITE_LOG(LOG_DEBUG, "%s free main session", __FUNCTION__);
353         if (checkSerialPort.data != nullptr) {
354             externInterface.TryCloseHandle((uv_handle_t *)&checkSerialPort);
355             checkSerialPort.data = nullptr;
356         }
357         CloseUartDevice();
358         WRITE_LOG(LOG_DEBUG, "%s free main session finish", __FUNCTION__);
359     }
360 }
361 } // namespace Hdc
362