1/*
2 * Copyright (c) 2022-2023 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 "miscdevice_dump.h"
17
18#include <getopt.h>
19
20#include <cinttypes>
21#include <cstring>
22#include <ctime>
23#include <map>
24
25#include "securec.h"
26#include "sensors_errors.h"
27
28#undef LOG_TAG
29#define LOG_TAG "MiscdeviceDump"
30
31namespace OHOS {
32namespace Sensors {
33namespace {
34constexpr uint32_t MAX_DUMP_RECORD_SIZE = 30;
35constexpr uint32_t BASE_YEAR = 1900;
36constexpr uint32_t BASE_MON = 1;
37constexpr int32_t MAX_DUMP_PARAMETERS = 32;
38constexpr int32_t CONVERSION_RATE = 1000;
39}  // namespace
40
41static std::map<int32_t, std::string> usageMap_ = {
42    {USAGE_UNKNOWN, "unknown"},
43    {USAGE_ALARM, "alarm"},
44    {USAGE_RING, "ring"},
45    {USAGE_NOTIFICATION, "notification"},
46    {USAGE_COMMUNICATION, "communication"},
47    {USAGE_TOUCH, "touch"},
48    {USAGE_MEDIA, "media"},
49    {USAGE_PHYSICAL_FEEDBACK, "physicalFeedback"},
50    {USAGE_SIMULATE_REALITY, "simulateReality"},
51};
52
53MiscdeviceDump::MiscdeviceDump() {}
54
55MiscdeviceDump::~MiscdeviceDump() {}
56
57void MiscdeviceDump::ParseCommand(int32_t fd, const std::vector<std::string> &args)
58{
59    int32_t count = 0;
60    for (const auto &str : args) {
61        if (str.find("--") == 0) {
62            ++count;
63            continue;
64        }
65        if (str.find("-") == 0) {
66            count += static_cast<int32_t>(str.size()) - 1;
67            continue;
68        }
69    }
70    if (count > MAX_DUMP_PARAMETERS) {
71        MISC_HILOGE("Cmd param number not more than 32");
72        dprintf(fd, "Cmd param number not more than 32\n");
73        return;
74    }
75    int32_t optionIndex = 0;
76    char **argv = new (std::nothrow) char *[args.size()];
77    CHKPV(argv);
78    if (memset_s(argv, args.size() * sizeof(char *), 0, args.size() * sizeof(char *)) != EOK) {
79        MISC_HILOGE("Call memset_s failed");
80        delete[] argv;
81        return;
82    }
83    for (size_t i = 0; i < args.size(); ++i) {
84        argv[i] = new (std::nothrow) char[args[i].size() + 1];
85        if (argv[i] == nullptr) {
86            MISC_HILOGE("Alloc failure");
87            goto RELEASE_RES;
88        }
89        if (strcpy_s(argv[i], args[i].size() + 1, args[i].c_str()) != EOK) {
90            MISC_HILOGE("strcpy_s error");
91            goto RELEASE_RES;
92        }
93    }
94    RunVibratorDump(fd, optionIndex, args, argv);
95    RELEASE_RES:
96    for (size_t i = 0; i < args.size(); ++i) {
97        if (argv[i] != nullptr) {
98            delete[] argv[i];
99        }
100    }
101    delete[] argv;
102}
103
104void MiscdeviceDump::RunVibratorDump(int32_t fd, int32_t optionIndex, const std::vector<std::string> &args, char **argv)
105{
106    struct option dumpOptions[] = {
107        {"record", no_argument, 0, 'r'},
108        {"help", no_argument, 0, 'h'},
109        {NULL, 0, 0, 0}
110    };
111    optind = 1;
112    int32_t c;
113    while ((c = getopt_long(args.size(), argv, "rh", dumpOptions, &optionIndex)) != -1) {
114        switch (c) {
115            case 'r': {
116                DumpMiscdeviceRecord(fd);
117                break;
118            }
119            case 'h': {
120                DumpHelp(fd);
121                break;
122            }
123            default: {
124                dprintf(fd, "Unrecognized option, More info with: \"hidumper -s 3602 -a -h\"\n");
125                break;
126            }
127        }
128    }
129}
130
131void MiscdeviceDump::DumpHelp(int32_t fd)
132{
133    dprintf(fd, "Usage:\n");
134    dprintf(fd, "      -h, --help: dump help\n");
135    dprintf(fd, "      -r, --record: dump the list of vibrate recorded\n");
136}
137
138void MiscdeviceDump::DumpMiscdeviceRecord(int32_t fd)
139{
140    std::lock_guard<std::mutex> queueLock(recordQueueMutex_);
141    if (dumpQueue_.empty()) {
142        MISC_HILOGW("dumpQueue_ is empty");
143        return;
144    }
145    size_t length = dumpQueue_.size() > MAX_DUMP_RECORD_SIZE ? MAX_DUMP_RECORD_SIZE : dumpQueue_.size();
146    for (size_t i = 0; i < length; ++i) {
147        auto record = dumpQueue_.front();
148        dumpQueue_.push(record);
149        dumpQueue_.pop();
150        VibrateInfo info = record.info;
151        if (info.mode == "time") {
152            dprintf(fd, "startTime:%s | uid:%d | pid:%d | packageName:%s | duration:%d | usage:%s\n",
153                record.startTime.c_str(), info.uid, info.pid, info.packageName.c_str(),
154                info.duration, GetUsageName(info.usage).c_str());
155        } else if (info.mode == "preset") {
156            dprintf(fd, "startTime:%s | uid:%d | pid:%d | packageName:%s | effect:%s | count:%d | usage:%s\n",
157                record.startTime.c_str(), info.uid, info.pid, info.packageName.c_str(),
158                info.effect.c_str(), info.count, GetUsageName(info.usage).c_str());
159        } else {
160            dprintf(fd, "startTime:%s | uid:%d | pid:%d | packageName:%s | usage:%s\n",
161                record.startTime.c_str(), info.uid, info.pid, info.packageName.c_str(),
162                GetUsageName(info.usage).c_str());
163        }
164    }
165}
166
167void MiscdeviceDump::DumpCurrentTime(std::string &startTime)
168{
169    timespec curTime;
170    clock_gettime(CLOCK_REALTIME, &curTime);
171    struct tm *timeinfo = localtime(&(curTime.tv_sec));
172    CHKPV(timeinfo);
173    startTime.append(std::to_string(timeinfo->tm_year + BASE_YEAR)).append("-")
174        .append(std::to_string(timeinfo->tm_mon + BASE_MON)).append("-").append(std::to_string(timeinfo->tm_mday))
175        .append(" ").append(std::to_string(timeinfo->tm_hour)).append(":").append(std::to_string(timeinfo->tm_min))
176        .append(":").append(std::to_string(timeinfo->tm_sec)).append(".")
177        .append(std::to_string(curTime.tv_nsec / (CONVERSION_RATE * CONVERSION_RATE)));
178}
179
180void MiscdeviceDump::UpdateRecordQueue(const VibrateRecord &record)
181{
182    std::lock_guard<std::mutex> queueLock(recordQueueMutex_);
183    dumpQueue_.push(record);
184    if (dumpQueue_.size() > MAX_DUMP_RECORD_SIZE) {
185        dumpQueue_.pop();
186    }
187}
188
189void MiscdeviceDump::SaveVibrateRecord(const VibrateInfo &vibrateInfo)
190{
191    VibrateRecord record;
192    record.info = vibrateInfo;
193    DumpCurrentTime(record.startTime);
194    UpdateRecordQueue(record);
195}
196
197std::string MiscdeviceDump::GetUsageName(int32_t usage)
198{
199    auto it = usageMap_.find(usage);
200    if (it == usageMap_.end()) {
201        MISC_HILOGE("Usage:%{public}d is invalid", usage);
202        return {};
203    }
204    return it->second;
205}
206}  // namespace Sensors
207}  // namespace OHOS
208