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