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 <cstring>
20 #include <getopt.h>
21 #include <iomanip>
22 #include <map>
23 #include <sstream>
24
25 #include <ipc_skeleton.h>
26 #include "securec.h"
27 #include "string_ex.h"
28 #include "unique_fd.h"
29
30 #include "devicestatus_common.h"
31 #include "devicestatus_define.h"
32 #include "include/util.h"
33
34 #undef LOG_TAG
35 #define LOG_TAG "DeviceStatusDumper"
36
37 namespace OHOS {
38 namespace Msdp {
39 namespace DeviceStatus {
40 namespace {
41 constexpr size_t MAX_DEVICE_STATUS_SIZE { 10 };
42 } // namespace
43
DeviceStatusDumper()44 DeviceStatusDumper::DeviceStatusDumper() {}
~DeviceStatusDumper()45 DeviceStatusDumper::~DeviceStatusDumper() {}
46
Init(IContext * context)47 int32_t DeviceStatusDumper::Init(IContext *context)
48 {
49 CALL_DEBUG_ENTER;
50 CHKPR(context, RET_ERR);
51 context_ = context;
52 return RET_OK;
53 }
54
ParseCommand(int32_t fd,const std::vector<std::string> & args,const std::vector<Data> & datas)55 void DeviceStatusDumper::ParseCommand(int32_t fd, const std::vector<std::string> &args, const std::vector<Data> &datas)
56 {
57 constexpr size_t BUFSIZE { 1024 };
58 char buf[BUFSIZE] { "hidumper" };
59
60 std::vector<char *> argv(args.size() + 1);
61 argv[0] = buf;
62
63 size_t len = std::strlen(buf) + 1;
64 char *pbuf = buf + len;
65 size_t bufLen = sizeof(buf) - len;
66
67 for (size_t index = 0, cnt = args.size(); index < cnt; ++index) {
68 len = args[index].size() + 1;
69 if (len > bufLen) {
70 FI_HILOGE("Buffer overflow");
71 return;
72 }
73 args[index].copy(pbuf, args[index].size());
74 pbuf[args[index].size()] = '\0';
75
76 argv[index + 1] = pbuf;
77 pbuf += len;
78 bufLen -= len;
79 }
80
81 struct option dumpOptions[] {
82 { "help", no_argument, nullptr, 'h' },
83 { "subscribe", no_argument, nullptr, 's' },
84 { "list", no_argument, nullptr, 'l' },
85 { "current", no_argument, nullptr, 'c' },
86 { "coordination", no_argument, nullptr, 'o' },
87 { "drag", no_argument, nullptr, 'd' },
88 { "macroState", no_argument, nullptr, 'm' },
89 { nullptr, 0, nullptr, 0 }
90 };
91 optind = 0;
92
93 for (;;) {
94 int32_t opt = getopt_long(argv.size(), argv.data(), "+hslcodm", dumpOptions, nullptr);
95 if (opt < 0) {
96 break;
97 }
98 ExecutDump(fd, datas, opt);
99 }
100 }
101
ExecutDump(int32_t fd,const std::vector<Data> & datas,int32_t opt)102 void DeviceStatusDumper::ExecutDump(int32_t fd, const std::vector<Data> &datas, int32_t opt)
103 {
104 switch (opt) {
105 case 'h': {
106 DumpHelpInfo(fd);
107 break;
108 }
109 case 's': {
110 DumpDeviceStatusSubscriber(fd);
111 break;
112 }
113 case 'l': {
114 DumpDeviceStatusChanges(fd);
115 break;
116 }
117 case 'c': {
118 DumpDeviceStatusCurrentStatus(fd, datas);
119 break;
120 }
121 case 'o': {
122 #ifdef OHOS_BUILD_ENABLE_COORDINATION
123 dprintf(fd, "device coordination is not supported\n");
124 #endif // OHOS_BUILD_ENABLE_COORDINATION
125 break;
126 }
127 case 'd': {
128 CHKPV(context_);
129 context_->GetDragManager().Dump(fd);
130 break;
131 }
132 case 'm': {
133 DumpCheckDefine(fd);
134 break;
135 }
136 default: {
137 dprintf(fd, "cmd param is error\n");
138 DumpHelpInfo(fd);
139 break;
140 }
141 }
142 }
143
DumpDeviceStatusSubscriber(int32_t fd)144 void DeviceStatusDumper::DumpDeviceStatusSubscriber(int32_t fd)
145 {
146 CALL_DEBUG_ENTER;
147 std::unique_lock lock(mutex_);
148 if (appInfos_.empty()) {
149 FI_HILOGE("appInfos_ is empty");
150 return;
151 }
152 std::string startTime;
153 GetTimeStamp(startTime);
154 dprintf(fd, "Current time:%s \n", startTime.c_str());
155 for (const auto &item : appInfos_) {
156 for (const auto &appInfo : item.second) {
157 dprintf(fd, "startTime:%s | uid:%d | pid:%d | type:%s | packageName:%s\n",
158 appInfo->startTime.c_str(), appInfo->uid, appInfo->pid, GetStatusType(appInfo->type).c_str(),
159 appInfo->packageName.c_str());
160 }
161 }
162 }
163
DumpDeviceStatusChanges(int32_t fd)164 void DeviceStatusDumper::DumpDeviceStatusChanges(int32_t fd)
165 {
166 CALL_DEBUG_ENTER;
167 std::unique_lock lock(mutex_);
168 if (deviceStatusQueue_.empty()) {
169 FI_HILOGI("deviceStatusQueue_ is empty");
170 return;
171 }
172 std::string startTime;
173 GetTimeStamp(startTime);
174 dprintf(fd, "Current time:%s\n", startTime.c_str());
175 size_t length = deviceStatusQueue_.size() > MAX_DEVICE_STATUS_SIZE ?
176 MAX_DEVICE_STATUS_SIZE : deviceStatusQueue_.size();
177 for (size_t i = 0; i < length; ++i) {
178 auto record = deviceStatusQueue_.front();
179 CHKPC(record);
180 deviceStatusQueue_.push(record);
181 deviceStatusQueue_.pop();
182 dprintf(fd, "startTime:%s | type:%s | value:%s\n",
183 record->startTime.c_str(), GetStatusType(record->data.type).c_str(),
184 GetDeviceState(record->data.value).c_str());
185 }
186 }
187
DumpDeviceStatusCurrentStatus(int32_t fd,const std::vector<Data> & datas) const188 void DeviceStatusDumper::DumpDeviceStatusCurrentStatus(int32_t fd, const std::vector<Data> &datas) const
189 {
190 CALL_DEBUG_ENTER;
191 std::string startTime;
192 GetTimeStamp(startTime);
193 dprintf(fd, "Current time:%s\n", startTime.c_str());
194 dprintf(fd, "Current device status:\n");
195 if (datas.empty()) {
196 dprintf(fd, "No device status available\n");
197 return;
198 }
199 for (auto it = datas.begin(); it != datas.end(); ++it) {
200 if (it->value == VALUE_INVALID) {
201 continue;
202 }
203 dprintf(fd, "type:%s | state:%s\n",
204 GetStatusType(it->type).c_str(), GetDeviceState(it->value).c_str());
205 }
206 }
207
GetDeviceState(OnChangedValue value) const208 std::string DeviceStatusDumper::GetDeviceState(OnChangedValue value) const
209 {
210 std::string state;
211 switch (value) {
212 case VALUE_ENTER: {
213 state = "enter";
214 break;
215 }
216 case VALUE_EXIT: {
217 state = "exit";
218 break;
219 }
220 case VALUE_INVALID: {
221 state = "invalid";
222 break;
223 }
224 default: {
225 state = "unknown";
226 break;
227 }
228 }
229 return state;
230 }
231
GetStatusType(Type type) const232 std::string DeviceStatusDumper::GetStatusType(Type type) const
233 {
234 std::string stateType;
235 switch (type) {
236 case TYPE_ABSOLUTE_STILL: {
237 stateType = "absolute still";
238 break;
239 }
240 case TYPE_HORIZONTAL_POSITION: {
241 stateType = "horizontal position";
242 break;
243 }
244 case TYPE_VERTICAL_POSITION: {
245 stateType = "vertical position";
246 break;
247 }
248 case TYPE_LID_OPEN: {
249 stateType = "lid open";
250 break;
251 }
252 default: {
253 stateType = "unknown";
254 break;
255 }
256 }
257 return stateType;
258 }
259
DumpHelpInfo(int32_t fd) const260 void DeviceStatusDumper::DumpHelpInfo(int32_t fd) const
261 {
262 dprintf(fd, "Usage:\n");
263 dprintf(fd, " -h: dump help\n");
264 dprintf(fd, " -s: dump the subscribers\n");
265 dprintf(fd, " -l: dump the last 10 device status change\n");
266 dprintf(fd, " -c: dump the current device status\n");
267 dprintf(fd, " -o: dump the coordination status\n");
268 dprintf(fd, " -d: dump the drag status\n");
269 dprintf(fd, " -m, dump the macro state\n");
270 }
271
SaveAppInfo(std::shared_ptr<AppInfo> appInfo)272 void DeviceStatusDumper::SaveAppInfo(std::shared_ptr<AppInfo> appInfo)
273 {
274 CALL_DEBUG_ENTER;
275 CHKPV(appInfo);
276 GetTimeStamp(appInfo->startTime);
277 std::set<std::shared_ptr<AppInfo>> appInfos;
278 std::unique_lock lock(mutex_);
279 auto iter = appInfos_.find(appInfo->type);
280 if (iter == appInfos_.end()) {
281 if (appInfos.insert(appInfo).second) {
282 auto [_, ret] = appInfos_.insert(std::make_pair(appInfo->type, appInfos));
283 if (!ret) {
284 FI_HILOGW("type is duplicated");
285 }
286 }
287 } else {
288 if (!appInfos_[iter->first].insert(appInfo).second) {
289 FI_HILOGW("appInfo is duplicated");
290 }
291 }
292 }
293
RemoveAppInfo(std::shared_ptr<AppInfo> appInfo)294 void DeviceStatusDumper::RemoveAppInfo(std::shared_ptr<AppInfo> appInfo)
295 {
296 CALL_DEBUG_ENTER;
297 CHKPV(appInfo);
298 CHKPV(appInfo->callback);
299 std::unique_lock lock(mutex_);
300 auto appInfoSetIter = appInfos_.find(appInfo->type);
301 if (appInfoSetIter == appInfos_.end()) {
302 FI_HILOGE("Not exist %{public}d type appInfo", appInfo->type);
303 return;
304 }
305 FI_HILOGI("callbacklist type:%{public}d, size:%{public}zu, appInfoMap size:%{public}zu",
306 appInfo->type, appInfos_[appInfoSetIter->first].size(), appInfos_.size());
307 auto iter = appInfos_.find(appInfo->type);
308 if (iter == appInfos_.end()) {
309 FI_HILOGW("Remove app info is not exists");
310 return;
311 }
312 for (const auto &item : iter->second) {
313 if (item->pid == appInfo->pid) {
314 iter->second.erase(item);
315 break;
316 }
317 }
318 }
319
SaveBoomerangAppInfo(std::shared_ptr<BoomerangAppInfo> appInfo)320 void DeviceStatusDumper::SaveBoomerangAppInfo(std::shared_ptr<BoomerangAppInfo> appInfo)
321 {
322 CALL_DEBUG_ENTER;
323 CHKPV(appInfo);
324 GetTimeStamp(appInfo->startTime);
325 std::set<std::shared_ptr<BoomerangAppInfo>> appInfos;
326 std::unique_lock lock(mutex_);
327 auto iter = boomerangAppInfos_.find(appInfo->type);
328 if (iter == boomerangAppInfos_.end()) {
329 if (appInfos.insert(appInfo).second) {
330 auto [_, ret] = boomerangAppInfos_.insert(std::make_pair(appInfo->type, appInfos));
331 if (!ret) {
332 FI_HILOGW("type is duplicated");
333 }
334 }
335 } else {
336 if (!boomerangAppInfos_[iter->first].insert(appInfo).second) {
337 FI_HILOGW("appInfo is duplicated");
338 }
339 }
340 }
341
SetNotifyMetadatAppInfo(std::shared_ptr<BoomerangAppInfo> appInfo)342 void DeviceStatusDumper::SetNotifyMetadatAppInfo(std::shared_ptr<BoomerangAppInfo> appInfo)
343 {
344 CALL_DEBUG_ENTER;
345 notifyMetadatAppInfo_ = appInfo;
346 }
347
RemoveBoomerangAppInfo(std::shared_ptr<BoomerangAppInfo> appInfo)348 void DeviceStatusDumper::RemoveBoomerangAppInfo(std::shared_ptr<BoomerangAppInfo> appInfo)
349 {
350 CALL_DEBUG_ENTER;
351 CHKPV(appInfo);
352 CHKPV(appInfo->boomerangCallback);
353 std::unique_lock lock(mutex_);
354 auto appInfoSetIter = boomerangAppInfos_.find(appInfo->type);
355 if (appInfoSetIter == boomerangAppInfos_.end()) {
356 FI_HILOGE("Not exist %{public}d type boomerangAppInfo", appInfo->type);
357 return;
358 }
359 FI_HILOGI("callbacklist type:%{public}d, size:%{public}zu, boomerangAppInfoMap size:%{public}zu",
360 appInfo->type, boomerangAppInfos_[appInfoSetIter->first].size(), boomerangAppInfos_.size());
361 auto iter = boomerangAppInfos_.find(appInfo->type);
362 if (iter == boomerangAppInfos_.end()) {
363 FI_HILOGW("Remove boomerang app info is not exists");
364 return;
365 }
366 for (const auto &item : iter->second) {
367 if (item->pid == appInfo->pid) {
368 iter->second.erase(item);
369 break;
370 }
371 }
372 }
373
PushDeviceStatus(const Data & data)374 void DeviceStatusDumper::PushDeviceStatus(const Data &data)
375 {
376 CALL_DEBUG_ENTER;
377 std::unique_lock lock(mutex_);
378 auto record = std::make_shared<DeviceStatusRecord>();
379 GetTimeStamp(record->startTime);
380 record->data = data;
381 deviceStatusQueue_.push(record);
382 if (deviceStatusQueue_.size() > MAX_DEVICE_STATUS_SIZE) {
383 deviceStatusQueue_.pop();
384 }
385 }
386
GetPackageName(Security::AccessToken::AccessTokenID tokenId)387 std::string DeviceStatusDumper::GetPackageName(Security::AccessToken::AccessTokenID tokenId)
388 {
389 CALL_DEBUG_ENTER;
390 std::string packageName = "unknown";
391 int32_t tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
392 switch (tokenType) {
393 case Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE: {
394 Security::AccessToken::NativeTokenInfo tokenInfo;
395 if (Security::AccessToken::AccessTokenKit::GetNativeTokenInfo(tokenId, tokenInfo) != 0) {
396 FI_HILOGE("Get native token info fail");
397 return packageName;
398 }
399 packageName = tokenInfo.processName;
400 break;
401 }
402 case Security::AccessToken::ATokenTypeEnum::TOKEN_HAP: {
403 Security::AccessToken::HapTokenInfo hapInfo;
404 if (Security::AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, hapInfo) != RET_OK) {
405 FI_HILOGE("Get hap token info fail");
406 return packageName;
407 }
408 packageName = hapInfo.bundleName;
409 break;
410 }
411 default: {
412 FI_HILOGW("token type not match");
413 break;
414 }
415 }
416 return packageName;
417 }
418
DumpCheckDefine(int32_t fd)419 void DeviceStatusDumper::DumpCheckDefine(int32_t fd)
420 {
421 ChkDefineOutput(fd);
422 }
423
ChkDefineOutput(int32_t fd)424 void DeviceStatusDumper::ChkDefineOutput(int32_t fd)
425 {
426 CheckDefineOutput(fd, "Macro switch state:\n");
427 #ifdef OHOS_BUILD_ENABLE_COORDINATION
428 CheckDefineOutput(fd, "%-40s", "OHOS_BUILD_ENABLE_COORDINATION");
429 #endif // OHOS_BUILD_ENABLE_COORDINATION
430 }
431
432 template<class ...Ts>
CheckDefineOutput(int32_t fd,const char * fmt,Ts...args)433 void DeviceStatusDumper::CheckDefineOutput(int32_t fd, const char* fmt, Ts... args)
434 {
435 CALL_DEBUG_ENTER;
436 CHKPV(fmt);
437 char buf[MAX_PACKET_BUF_SIZE] = { 0 };
438 int32_t ret = snprintf_s(buf, MAX_PACKET_BUF_SIZE, MAX_PACKET_BUF_SIZE - 1, fmt, args...);
439 if (ret == -1) {
440 FI_HILOGE("Call snprintf_s failed, ret:%{public}d", ret);
441 return;
442 }
443 dprintf(fd, "%s", buf);
444 }
445 } // namespace DeviceStatus
446 } // namespace Msdp
447 } // namespace OHOS
448