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 
31 namespace OHOS {
32 namespace Sensors {
33 namespace {
34 constexpr uint32_t MAX_DUMP_RECORD_SIZE = 30;
35 constexpr uint32_t BASE_YEAR = 1900;
36 constexpr uint32_t BASE_MON = 1;
37 constexpr int32_t MAX_DUMP_PARAMETERS = 32;
38 constexpr int32_t CONVERSION_RATE = 1000;
39 }  // namespace
40 
41 static 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 
MiscdeviceDump()53 MiscdeviceDump::MiscdeviceDump() {}
54 
~MiscdeviceDump()55 MiscdeviceDump::~MiscdeviceDump() {}
56 
ParseCommand(int32_t fd,const std::vector<std::string> & args)57 void 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 
RunVibratorDump(int32_t fd,int32_t optionIndex,const std::vector<std::string> & args,char ** argv)104 void 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 
DumpHelp(int32_t fd)131 void 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 
DumpMiscdeviceRecord(int32_t fd)138 void 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 
DumpCurrentTime(std::string & startTime)167 void 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 
UpdateRecordQueue(const VibrateRecord & record)180 void 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 
SaveVibrateRecord(const VibrateInfo & vibrateInfo)189 void MiscdeviceDump::SaveVibrateRecord(const VibrateInfo &vibrateInfo)
190 {
191     VibrateRecord record;
192     record.info = vibrateInfo;
193     DumpCurrentTime(record.startTime);
194     UpdateRecordQueue(record);
195 }
196 
GetUsageName(int32_t usage)197 std::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