1/*
2 * Copyright (c) 2024 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
16#include "msdpdevicemanager_fuzzer.h"
17#include "ddm_adapter.h"
18#include "devicestatus_define.h"
19
20#undef LOG_TAG
21#define LOG_TAG "MsdpDeviceManagerFuzzTest"
22namespace OHOS {
23namespace Msdp {
24namespace DeviceStatus {
25namespace {
26struct DeviceStatusEpollEvent {
27    int32_t fd { -1 };
28    EpollEventType eventType { EPOLL_EVENT_BEGIN };
29};
30
31const uint8_t *g_baseFuzzData = nullptr;
32size_t g_baseFuzzSize = 0;
33size_t g_baseFuzzPos = 0;
34constexpr size_t STR_LEN = 255;
35ContextService *g_instance = nullptr;
36constexpr int32_t DEFAULT_WAIT_TIME_MS { 1000 };
37constexpr int32_t WAIT_FOR_ONCE { 1 };
38constexpr int32_t MAX_N_RETRIES { 100 };
39} // namespace
40
41ContextService::ContextService()
42{
43    ddm_ = std::make_unique<DDMAdapter>();
44
45    OnStart();
46}
47
48ContextService::~ContextService()
49{
50    OnStop();
51}
52
53IDelegateTasks& ContextService::GetDelegateTasks()
54{
55    return delegateTasks_;
56}
57
58IDeviceManager& ContextService::GetDeviceManager()
59{
60    return devMgr_;
61}
62
63ITimerManager& ContextService::GetTimerManager()
64{
65    return timerMgr_;
66}
67
68IDragManager& ContextService::GetDragManager()
69{
70    return dragMgr_;
71}
72
73ContextService* ContextService::GetInstance()
74{
75    static std::once_flag flag;
76    std::call_once(flag, [&]() {
77        ContextService *cooContext = new (std::nothrow) ContextService();
78        CHKPL(cooContext);
79        g_instance = cooContext;
80    });
81    return g_instance;
82}
83
84ISocketSessionManager& ContextService::GetSocketSessionManager()
85{
86    return socketSessionMgr_;
87}
88
89IDDMAdapter& ContextService::GetDDM()
90{
91    return *ddm_;
92}
93
94IPluginManager& ContextService::GetPluginManager()
95{
96    return *pluginMgr_;
97}
98
99IInputAdapter& ContextService::GetInput()
100{
101    return *input_;
102}
103
104IDSoftbusAdapter& ContextService::GetDSoftbus()
105{
106    return *dsoftbusAda_;
107}
108
109bool ContextService::Init()
110{
111    CALL_DEBUG_ENTER;
112    if (EpollCreate() != RET_OK) {
113        FI_HILOGE("Create epoll failed");
114        return false;
115    }
116    if (InitDelegateTasks() != RET_OK) {
117        FI_HILOGE("Delegate tasks init failed");
118        goto INIT_FAIL;
119    }
120    if (InitTimerMgr() != RET_OK) {
121        FI_HILOGE("TimerMgr init failed");
122        goto INIT_FAIL;
123    }
124    if (InitDevMgr() != RET_OK) {
125        FI_HILOGE("DevMgr init failed");
126        goto INIT_FAIL;
127    }
128
129    return true;
130
131INIT_FAIL:
132    EpollClose();
133    return false;
134}
135int32_t ContextService::InitDevMgr()
136{
137    CALL_DEBUG_ENTER;
138    int32_t ret = devMgr_.Init(this);
139    if (ret != RET_OK) {
140        FI_HILOGE("DevMgr init failed");
141        return ret;
142    }
143    return ret;
144}
145
146int32_t ContextService::InitTimerMgr()
147{
148    CALL_DEBUG_ENTER;
149    int32_t ret = timerMgr_.Init(this);
150    if (ret != RET_OK) {
151        FI_HILOGE("TimerMgr init failed");
152        return ret;
153    }
154
155    ret = AddEpoll(EPOLL_EVENT_TIMER, timerMgr_.GetTimerFd());
156    if (ret != RET_OK) {
157        FI_HILOGE("AddEpoll for timer failed");
158    }
159    return ret;
160}
161
162int32_t ContextService::InitDelegateTasks()
163{
164    CALL_DEBUG_ENTER;
165    if (!delegateTasks_.Init()) {
166        FI_HILOGE("The delegate task init failed");
167        return RET_ERR;
168    }
169    int32_t ret = AddEpoll(EPOLL_EVENT_ETASK, delegateTasks_.GetReadFd());
170    if (ret != RET_OK) {
171        FI_HILOGE("AddEpoll error ret:%{public}d", ret);
172    }
173    FI_HILOGI("AddEpoll, epollfd:%{public}d, fd:%{public}d", epollFd_, delegateTasks_.GetReadFd());
174    return ret;
175}
176
177int32_t ContextService::EpollCreate()
178{
179    CALL_DEBUG_ENTER;
180    epollFd_ = ::epoll_create1(EPOLL_CLOEXEC);
181    if (epollFd_ < 0) {
182        FI_HILOGE("epoll_create1 failed:%{public}s", ::strerror(errno));
183        return RET_ERR;
184    }
185    return RET_OK;
186}
187
188int32_t ContextService::AddEpoll(EpollEventType type, int32_t fd)
189{
190    CALL_DEBUG_ENTER;
191    if (!(type >= EPOLL_EVENT_BEGIN && type < EPOLL_EVENT_END)) {
192        FI_HILOGE("Invalid type:%{public}d", type);
193        return RET_ERR;
194    }
195    if (fd < 0) {
196        FI_HILOGE("Invalid fd:%{public}d", fd);
197        return RET_ERR;
198    }
199    auto eventData = static_cast<DeviceStatusEpollEvent*>(malloc(sizeof(DeviceStatusEpollEvent)));
200    if (!eventData) {
201        FI_HILOGE("Malloc failed");
202        return RET_ERR;
203    }
204    eventData->fd = fd;
205    eventData->eventType = type;
206    FI_HILOGD("EventData:[fd:%{public}d, type:%{public}d]", eventData->fd, eventData->eventType);
207
208    struct epoll_event ev {};
209    ev.events = EPOLLIN;
210    ev.data.ptr = eventData;
211    if (EpollCtl(fd, EPOLL_CTL_ADD, ev) != RET_OK) {
212        free(eventData);
213        eventData = nullptr;
214        ev.data.ptr = nullptr;
215        FI_HILOGE("EpollCtl failed");
216        return RET_ERR;
217    }
218    return RET_OK;
219}
220
221int32_t ContextService::DelEpoll(EpollEventType type, int32_t fd)
222{
223    CALL_DEBUG_ENTER;
224    if (!(type >= EPOLL_EVENT_BEGIN && type < EPOLL_EVENT_END)) {
225        FI_HILOGE("Invalid type:%{public}d", type);
226        return RET_ERR;
227    }
228    if (fd < 0) {
229        FI_HILOGE("Invalid fd:%{public}d", fd);
230        return RET_ERR;
231    }
232    struct epoll_event ev {};
233    if (EpollCtl(fd, EPOLL_CTL_DEL, ev) != RET_OK) {
234        FI_HILOGE("DelEpoll failed");
235        return RET_ERR;
236    }
237    return RET_OK;
238}
239
240void ContextService::EpollClose()
241{
242    CALL_DEBUG_ENTER;
243    if (epollFd_ >= 0) {
244        if (close(epollFd_) < 0) {
245            FI_HILOGE("Close epoll fd failed, error:%{public}s, epollFd_:%{public}d", strerror(errno), epollFd_);
246        }
247        epollFd_ = -1;
248    }
249}
250
251int32_t ContextService::EpollCtl(int32_t fd, int32_t op, struct epoll_event &event)
252{
253    CALL_DEBUG_ENTER;
254    if (fd < 0) {
255        FI_HILOGE("Invalid fd:%{public}d", fd);
256        return RET_ERR;
257    }
258    if (epollFd_ < 0) {
259        FI_HILOGE("Invalid epollFd:%{public}d", epollFd_);
260        return RET_ERR;
261    }
262    if (::epoll_ctl(epollFd_, op, fd, &event) != 0) {
263        FI_HILOGE("epoll_ctl(%{public}d,%{public}d,%{public}d) failed:%{public}s", epollFd_, op, fd, ::strerror(errno));
264        return RET_ERR;
265    }
266    return RET_OK;
267}
268
269int32_t ContextService::EpollWait(int32_t maxevents, int32_t timeout, struct epoll_event &events)
270{
271    if (epollFd_ < 0) {
272        FI_HILOGE("Invalid epollFd:%{public}d", epollFd_);
273        return RET_ERR;
274    }
275    return epoll_wait(epollFd_, &events, maxevents, timeout);
276}
277
278void ContextService::OnTimeout(const struct epoll_event &ev)
279{
280    CALL_DEBUG_ENTER;
281    if ((ev.events & EPOLLIN) == EPOLLIN) {
282        uint64_t expiration {};
283        ssize_t ret = read(timerMgr_.GetTimerFd(), &expiration, sizeof(expiration));
284        if (ret < 0) {
285            FI_HILOGE("Read expiration failed:%{public}s", strerror(errno));
286        }
287        timerMgr_.ProcessTimers();
288    } else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
289        FI_HILOGE("Epoll hangup:%{public}s", strerror(errno));
290    }
291}
292
293void ContextService::OnDeviceMgr(const struct epoll_event &ev)
294{
295    CALL_DEBUG_ENTER;
296    if ((ev.events & EPOLLIN) == EPOLLIN) {
297        devMgr_.Dispatch(ev);
298    } else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
299        FI_HILOGE("Epoll hangup:%{public}s", strerror(errno));
300    }
301}
302
303int32_t ContextService::EnableDevMgr(int32_t nRetries)
304{
305    CALL_INFO_TRACE;
306    static int32_t timerId { -1 };
307    int32_t ret = devMgr_.Enable();
308    if (ret != RET_OK) {
309        FI_HILOGE("Failed to enable device manager");
310        if (nRetries > 0) {
311            timerId = timerMgr_.AddTimer(DEFAULT_WAIT_TIME_MS, WAIT_FOR_ONCE,
312                [this, nRetries] { return this->EnableDevMgr(nRetries - 1); });
313            if (timerId < 0) {
314                FI_HILOGE("AddTimer failed, Failed to enable device manager");
315            }
316        } else {
317            FI_HILOGE("Maximum number of retries exceeded, Failed to enable device manager");
318        }
319        return ret;
320    }
321    AddEpoll(EPOLL_EVENT_DEVICE_MGR, devMgr_.GetFd());
322    if (timerId >= 0) {
323        timerMgr_.RemoveTimer(timerId);
324        timerId = -1;
325    }
326    return RET_OK;
327}
328
329void ContextService::DisableDevMgr()
330{
331    DelEpoll(EPOLL_EVENT_DEVICE_MGR, devMgr_.GetFd());
332    devMgr_.Disable();
333}
334
335void ContextService::OnStart()
336{
337    CALL_DEBUG_ENTER;
338    uint64_t tid = GetThisThreadId();
339    delegateTasks_.SetWorkerThreadId(tid);
340
341    if (!Init()) {
342        FI_HILOGE("On start call init failed");
343        return;
344    }
345    state_ = ServiceRunningState::STATE_RUNNING;
346    ready_ = true;
347
348    worker_ = std::thread(std::bind(&ContextService::OnThread, this));
349}
350
351void ContextService::OnStop()
352{
353    CALL_DEBUG_ENTER;
354    if (timerMgr_.GetTimerFd() >= 0) {
355        if (close(timerMgr_.GetTimerFd()) < 0) {
356            FI_HILOGE("Close timer fd failed, error:%{public}s", strerror(errno));
357        }
358    }
359    if (!ready_) {
360        FI_HILOGI("ready state is false");
361        return;
362    }
363    ready_ = false;
364    state_ = ServiceRunningState::STATE_EXIT;
365
366    delegateTasks_.PostAsyncTask([]() -> int32_t {
367        FI_HILOGD("No asynchronous operations");
368        return RET_OK;
369    });
370    if (worker_.joinable()) {
371        worker_.join();
372    }
373    DisableDevMgr();
374    EpollClose();
375    FI_HILOGI("OnStop leave");
376}
377
378void ContextService::OnThread()
379{
380    CALL_DEBUG_ENTER;
381    SetThreadName(std::string("os_ds_service"));
382    uint64_t tid = GetThisThreadId();
383    delegateTasks_.SetWorkerThreadId(tid);
384    EnableDevMgr(MAX_N_RETRIES);
385    FI_HILOGD("Main worker thread start, tid:%{public}" PRId64 "", tid);
386
387    while (state_ == ServiceRunningState::STATE_RUNNING) {
388        struct epoll_event ev[MAX_EVENT_SIZE] {};
389        int32_t count = EpollWait(MAX_EVENT_SIZE, -1, ev[0]);
390        for (int32_t i = 0; i < count && state_ == ServiceRunningState::STATE_RUNNING; i++) {
391            auto epollEvent = reinterpret_cast<DeviceStatusEpollEvent*>(ev[i].data.ptr);
392            CHKPC(epollEvent);
393            if (epollEvent->eventType == EPOLL_EVENT_TIMER) {
394                OnTimeout(ev[i]);
395            } else if (epollEvent->eventType == EPOLL_EVENT_ETASK) {
396                OnDelegateTask(ev[i]);
397            } else if (epollEvent->eventType == EPOLL_EVENT_DEVICE_MGR) {
398                OnDeviceMgr(ev[i]);
399            } else {
400                FI_HILOGW("Unknown epoll event type:%{public}d", epollEvent->eventType);
401            }
402        }
403    }
404    FI_HILOGD("Main worker thread stop, tid:%{public}" PRId64 "", tid);
405}
406
407void ContextService::OnDelegateTask(const struct epoll_event &ev)
408{
409    if ((ev.events & EPOLLIN) == 0) {
410        FI_HILOGW("Not epollin");
411        return;
412    }
413    DelegateTasks::TaskData data {};
414    ssize_t res = read(delegateTasks_.GetReadFd(), &data, sizeof(data));
415    if (res == -1) {
416        FI_HILOGW("Read failed erron:%{public}d", errno);
417    }
418    FI_HILOGD("RemoteRequest notify td:%{public}" PRId64 ", std:%{public}" PRId64 ""
419        ", taskId:%{public}d", GetThisThreadId(), data.tid, data.taskId);
420    delegateTasks_.ProcessTasks();
421}
422
423template <class T> T GetData()
424{
425    T objetct{};
426    size_t objetctSize = sizeof(objetct);
427    if (g_baseFuzzData == nullptr || objetctSize > g_baseFuzzSize - g_baseFuzzPos) {
428        return objetct;
429    }
430    errno_t ret = memcpy_s(&objetct, objetctSize, g_baseFuzzData + g_baseFuzzPos, objetctSize);
431    if (ret != EOK) {
432        return {};
433    }
434    g_baseFuzzPos += objetctSize;
435    return objetct;
436}
437
438void SetGlobalFuzzData(const uint8_t *data, size_t size)
439{
440    g_baseFuzzData = data;
441    g_baseFuzzSize = size;
442    g_baseFuzzPos = 0;
443}
444
445std::string GetStringFromData(int strlen)
446{
447    if (strlen < 1) {
448        return "";
449    }
450
451    char cstr[strlen];
452    cstr[strlen - 1] = '\0';
453    for (int i = 0; i < strlen - 1; i++) {
454        cstr[i] = GetData<char>();
455    }
456    std::string str(cstr);
457    return str;
458}
459
460bool MsdpDeviceManagerFuzzTest(const uint8_t* data, size_t size)
461{
462    if ((data == nullptr) || (size < 1)) {
463        return false;
464    }
465    SetGlobalFuzzData(data, size);
466
467    std::string devStr = GetStringFromData(STR_LEN);
468    int32_t id = GetData<int32_t>();
469
470    struct epoll_event ev {};
471    std::weak_ptr<IDeviceObserver> weakObserver = std::weak_ptr<IDeviceObserver>();
472    auto env = ContextService::GetInstance();
473
474    env->devMgr_.AddDevice(devStr);
475    env->devMgr_.FindDevice(devStr);
476    env->devMgr_.ParseDeviceId(devStr);
477    env->devMgr_.Dispatch(ev);
478    env->GetDeviceManager().GetDevice(id);
479    env->GetDeviceManager().RetriggerHotplug(weakObserver);
480    env->GetDeviceManager().AddDeviceObserver(weakObserver);
481    env->GetDeviceManager().RemoveDeviceObserver(weakObserver);
482    env->devMgr_.HasLocalPointerDevice();
483    env->devMgr_.HasLocalKeyboardDevice();
484    env->devMgr_.HasKeyboard();
485    env->devMgr_.GetKeyboard();
486    env->devMgr_.RemoveDevice(devStr);
487    return true;
488}
489
490extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
491{
492    /* Run your code on data */
493    if (data == nullptr) {
494        return 0;
495    }
496
497    OHOS::Msdp::DeviceStatus::MsdpDeviceManagerFuzzTest(data, size);
498
499    return 0;
500}
501} // namespace DeviceStatus
502} // namespace Msdp
503} // namespace OHOS