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