• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "devicestatus_dumper.h"
17 
18 #include <cinttypes>
19 #include <csignal>
20 #include <cstring>
21 #include <getopt.h>
22 #include <iomanip>
23 #include <map>
24 #include <sstream>
25 
26 #include "securec.h"
27 #include "string_ex.h"
28 #include "unique_fd.h"
29 
30 #include "devicestatus_common.h"
31 
32 namespace OHOS {
33 namespace Msdp {
34 namespace {
35     constexpr uint32_t MS_NS = 1000000;
36 }
ParseCommand(int32_t fd,const std::vector<std::string> & args,const std::vector<DevicestatusDataUtils::DevicestatusData> & datas)37 void DevicestatusDumper::ParseCommand(int32_t fd, const std::vector<std::string> &args,
38     const std::vector<DevicestatusDataUtils::DevicestatusData> &datas)
39 {
40     int32_t optionIndex = 0;
41     struct option dumpOptions[] = {
42         {"help", no_argument, 0, 'h'},
43         {"subscribe", no_argument, 0, 's'},
44         {"list", no_argument, 0, 'l'},
45         {"current", no_argument, 0, 'c'},
46         {NULL, 0, 0, 0}
47     };
48     char **argv = new char *[args.size()];
49     for (size_t i = 0; i < args.size(); ++i) {
50         argv[i] = new char[args[i].size() + 1];
51         if (strcpy_s(argv[i], args[i].size() + 1, args[i].c_str()) != RET_OK) {
52             DEV_HILOGE(SERVICE, "strcpy_s error");
53             goto RELEASE_RES;
54             return;
55         }
56     }
57     optind = 1;
58     int32_t c;
59     while ((c = getopt_long(args.size(), argv, "hslc", dumpOptions, &optionIndex)) != -1) {
60         switch (c) {
61             case 'h': {
62                 DumpHelpInfo(fd);
63                 break;
64             }
65             case 's': {
66                 DumpDevicestatusSubscriber(fd);
67                 break;
68             }
69             case 'l': {
70                 DumpDevicestatusChanges(fd);
71                 break;
72             }
73             case 'c': {
74                 DumpDevicestatusCurrentStatus(fd, datas);
75                 break;
76             }
77             default: {
78                 dprintf(fd, "cmd param is error\n");
79                 DumpHelpInfo(fd);
80                 break;
81             }
82         }
83     }
84     RELEASE_RES:
85     for (size_t i = 0; i < args.size(); ++i) {
86         delete[] argv[i];
87     }
88     delete[] argv;
89 }
90 
DumpDevicestatusSubscriber(int32_t fd)91 void DevicestatusDumper::DumpDevicestatusSubscriber(int32_t fd)
92 {
93     DEV_HILOGI(SERVICE, "start");
94     if (appInfoMap_.empty()) {
95         DEV_HILOGI(SERVICE, "appInfoMap_ is empty");
96         return;
97     }
98     std::string startTime;
99     DumpCurrentTime(startTime);
100     dprintf(fd, "Current time: %s \n", startTime.c_str());
101     for (const auto &item : appInfoMap_) {
102         for (auto appInfo : item.second) {
103             dprintf(fd, "startTime:%s | uid:%d | pid:%d | type:%s | packageName:%s\n",
104                 appInfo->startTime.c_str(), appInfo->uid, appInfo->pid, GetStatusType(appInfo->type).c_str(),
105                 appInfo->packageName.c_str());
106         }
107     }
108 }
109 
DumpDevicestatusChanges(int32_t fd)110 void DevicestatusDumper::DumpDevicestatusChanges(int32_t fd)
111 {
112     DEV_HILOGI(SERVICE, "start");
113     if (deviceStatusQueue_.empty()) {
114         DEV_HILOGI(SERVICE, "deviceStatusQueue_ is empty");
115         return;
116     }
117     std::string startTime;
118     DumpCurrentTime(startTime);
119     dprintf(fd, "Current time: %s \n", startTime.c_str());
120     size_t length = deviceStatusQueue_.size() > MAX_DEVICE_STATUS_SIZE ? \
121         MAX_DEVICE_STATUS_SIZE : deviceStatusQueue_.size();
122     for (size_t i = 0; i < length; ++i) {
123         auto record = deviceStatusQueue_.front();
124         if (record == nullptr) {
125             DEV_HILOGI(SERVICE, "deviceStatusQueue_ is is null");
126             continue;
127         }
128         deviceStatusQueue_.push(record);
129         deviceStatusQueue_.pop();
130         dprintf(fd, "startTime:%s | type:%s | value:%s \n",
131             record->startTime.c_str(), GetStatusType(record->data.type).c_str(),
132             GetDeviceState(record->data.value).c_str());
133     }
134 }
135 
DumpDevicestatusCurrentStatus(int32_t fd,const std::vector<DevicestatusDataUtils::DevicestatusData> & datas) const136 void DevicestatusDumper::DumpDevicestatusCurrentStatus(int32_t fd,
137     const std::vector<DevicestatusDataUtils::DevicestatusData> &datas) const
138 {
139     DEV_HILOGI(SERVICE, "start");
140     std::string startTime;
141     DumpCurrentTime(startTime);
142     dprintf(fd, "Current time: %s \n", startTime.c_str());
143     dprintf(fd, "Current device status: \n");
144     if (datas.empty()) {
145         dprintf(fd, "No device status available\n");
146         return;
147     }
148     for (auto it = datas.begin(); it != datas.end(); ++it) {
149         if (it->value == DevicestatusDataUtils::VALUE_INVALID) {
150             continue;
151         }
152         dprintf(fd, "Device status DevicestatusType is %s , current type state is %s .\n",
153             GetStatusType(it->type).c_str(), GetDeviceState(it->value).c_str());
154     }
155 }
156 
GetDeviceState(const DevicestatusDataUtils::DevicestatusValue & value) const157 std::string DevicestatusDumper::GetDeviceState(const DevicestatusDataUtils::DevicestatusValue &value) const
158 {
159     std::string state;
160     switch (value) {
161         case DevicestatusDataUtils::VALUE_ENTER: {
162             state = "enter";
163             break;
164         }
165         case DevicestatusDataUtils::VALUE_EXIT: {
166             state = "exit";
167             break;
168         }
169         case DevicestatusDataUtils::VALUE_INVALID: {
170             state = "invalid";
171             break;
172         }
173         default: {
174             state = "unknown";
175             break;
176         }
177     }
178     return state;
179 }
180 
GetStatusType(const DevicestatusDataUtils::DevicestatusType & type) const181 std::string DevicestatusDumper::GetStatusType(const DevicestatusDataUtils::DevicestatusType &type) const
182 {
183     std::string stateType;
184     switch (type) {
185         case DevicestatusDataUtils::TYPE_STILL: {
186             stateType = "high still";
187             break;
188         }
189         case DevicestatusDataUtils::TYPE_RELATIVE_STILL: {
190             stateType = "fine still";
191             break;
192         }
193         case DevicestatusDataUtils::TYPE_CAR_BLUETOOTH: {
194             stateType = "car bluetooth";
195             break;
196         }
197         case DevicestatusDataUtils::TYPE_LID_OPEN: {
198             stateType = "lid open";
199             break;
200         }
201         default: {
202             stateType = "unknown";
203             break;
204         }
205     }
206     return stateType;
207 }
208 
DumpCurrentTime(std::string & startTime) const209 void DevicestatusDumper::DumpCurrentTime(std::string &startTime) const
210 {
211     timespec curTime;
212     clock_gettime(CLOCK_REALTIME, &curTime);
213     struct tm *timeinfo = localtime(&(curTime.tv_sec));
214     if (timeinfo == nullptr) {
215         DEV_HILOGI(SERVICE, "get localtime failed");
216         return;
217     }
218     startTime.append(std::to_string(timeinfo->tm_year + BASE_YEAR)).append("-")
219         .append(std::to_string(timeinfo->tm_mon + BASE_MON)).append("-").append(std::to_string(timeinfo->tm_mday))
220         .append(" ").append(std::to_string(timeinfo->tm_hour)).append(":").append(std::to_string(timeinfo->tm_min))
221         .append(":").append(std::to_string(timeinfo->tm_sec)).append(".")
222         .append(std::to_string(curTime.tv_nsec / MS_NS));
223 }
224 
DumpHelpInfo(int32_t fd) const225 void DevicestatusDumper::DumpHelpInfo(int32_t fd) const
226 {
227     dprintf(fd, "Usage:\n");
228     dprintf(fd, "      -h: dump help\n");
229     dprintf(fd, "      -s: dump the device_status subscribers\n");
230     dprintf(fd, "      -l: dump the last 10 device status change\n");
231     dprintf(fd, "      -c: dump the device_status current device status\n");
232 }
233 
SaveAppInfo(std::shared_ptr<AppInfo> appInfo)234 void DevicestatusDumper::SaveAppInfo(std::shared_ptr<AppInfo> appInfo)
235 {
236     DEV_HILOGI(SERVICE, "Enter");
237     DumpCurrentTime(appInfo->startTime);
238     std::set<std::shared_ptr<AppInfo>> appInfos;
239     auto iter = appInfoMap_.find(appInfo->type);
240     if (iter == appInfoMap_.end()) {
241         if (appInfos.insert(appInfo).second) {
242             appInfoMap_.insert(std::make_pair(appInfo->type, appInfos));
243         }
244     } else {
245         if (!appInfoMap_[iter->first].insert(appInfo).second) {
246             DEV_HILOGW(SERVICE, "duplicated app info");
247             return;
248         }
249     }
250 }
251 
RemoveAppInfo(std::shared_ptr<AppInfo> appInfo)252 void DevicestatusDumper::RemoveAppInfo(std::shared_ptr<AppInfo> appInfo)
253 {
254     DEV_HILOGI(SERVICE, "Enter");
255     if (appInfo->callback == nullptr) {
256         DEV_HILOGW(SERVICE, "callback is null");
257         return;
258     }
259     DEV_HILOGI(SERVICE, "appInfoMap_ size=%{public}zu", appInfoMap_.size());
260 
261     auto appInfoSetIter = appInfoMap_.find(appInfo->type);
262     if (appInfoSetIter == appInfoMap_.end()) {
263         DEV_HILOGE(SERVICE, "not exist %d type appInfo", appInfo->type);
264         return;
265     }
266     DEV_HILOGI(SERVICE, "callbacklist type=%d size=%{public}zu",
267         appInfo->type, appInfoMap_[appInfoSetIter->first].size());
268     auto iter = appInfoMap_.find(appInfo->type);
269     if (iter == appInfoMap_.end()) {
270         DEV_HILOGW(SERVICE, "Remove app info is not exists");
271         return;
272     }
273     for (const auto &item : iter->second) {
274         if (item->pid == appInfo->pid) {
275             iter->second.erase(item);
276             break;
277         }
278     }
279 }
280 
pushDeviceStatus(const DevicestatusDataUtils::DevicestatusData & data)281 void DevicestatusDumper::pushDeviceStatus(const DevicestatusDataUtils::DevicestatusData& data)
282 {
283     DEV_HILOGI(SERVICE, "Enter");
284     std::unique_lock lock(mutex_);
285     auto record = std::make_shared<DeviceStatusRecord>();
286     DumpCurrentTime(record->startTime);
287     record->data = data;
288     deviceStatusQueue_.push(record);
289     if (deviceStatusQueue_.size() > MAX_DEVICE_STATUS_SIZE) {
290         deviceStatusQueue_.pop();
291     }
292 }
293 } // namespace Msdp
294 } // namespace OHOS