• 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     if (appInfoMap_.empty()) {
152         FI_HILOGE("appInfoMap_ is empty");
153         return;
154     }
155     std::string startTime;
156     GetTimeStamp(startTime);
157     dprintf(fd, "Current time:%s \n", startTime.c_str());
158     for (const auto &item : appInfoMap_) {
159         for (auto appInfo : item.second) {
160             dprintf(fd, "startTime:%s | uid:%d | pid:%d | type:%s | packageName:%s\n",
161                 appInfo->startTime.c_str(), appInfo->uid, appInfo->pid, GetStatusType(appInfo->type).c_str(),
162                 appInfo->packageName.c_str());
163         }
164     }
165 }
166 
DumpDeviceStatusChanges(int32_t fd)167 void DeviceStatusDumper::DumpDeviceStatusChanges(int32_t fd)
168 {
169     CALL_DEBUG_ENTER;
170     if (deviceStatusQueue_.empty()) {
171         FI_HILOGI("deviceStatusQueue_ is empty");
172         return;
173     }
174     std::string startTime;
175     GetTimeStamp(startTime);
176     dprintf(fd, "Current time:%s\n", startTime.c_str());
177     size_t length = deviceStatusQueue_.size() > MAX_DEVICE_STATUS_SIZE ?
178         MAX_DEVICE_STATUS_SIZE : deviceStatusQueue_.size();
179     for (size_t i = 0; i < length; ++i) {
180         auto record = deviceStatusQueue_.front();
181         CHKPC(record);
182         deviceStatusQueue_.push(record);
183         deviceStatusQueue_.pop();
184         dprintf(fd, "startTime:%s | type:%s | value:%s\n",
185             record->startTime.c_str(), GetStatusType(record->data.type).c_str(),
186             GetDeviceState(record->data.value).c_str());
187     }
188 }
189 
DumpDeviceStatusCurrentStatus(int32_t fd,const std::vector<Data> & datas) const190 void DeviceStatusDumper::DumpDeviceStatusCurrentStatus(int32_t fd, const std::vector<Data> &datas) const
191 {
192     CALL_DEBUG_ENTER;
193     std::string startTime;
194     GetTimeStamp(startTime);
195     dprintf(fd, "Current time:%s\n", startTime.c_str());
196     dprintf(fd, "Current device status:\n");
197     if (datas.empty()) {
198         dprintf(fd, "No device status available\n");
199         return;
200     }
201     for (auto it = datas.begin(); it != datas.end(); ++it) {
202         if (it->value == VALUE_INVALID) {
203             continue;
204         }
205         dprintf(fd, "type:%s | state:%s\n",
206             GetStatusType(it->type).c_str(), GetDeviceState(it->value).c_str());
207     }
208 }
209 
GetDeviceState(OnChangedValue value) const210 std::string DeviceStatusDumper::GetDeviceState(OnChangedValue value) const
211 {
212     std::string state;
213     switch (value) {
214         case VALUE_ENTER: {
215             state = "enter";
216             break;
217         }
218         case VALUE_EXIT: {
219             state = "exit";
220             break;
221         }
222         case VALUE_INVALID: {
223             state = "invalid";
224             break;
225         }
226         default: {
227             state = "unknown";
228             break;
229         }
230     }
231     return state;
232 }
233 
GetStatusType(Type type) const234 std::string DeviceStatusDumper::GetStatusType(Type type) const
235 {
236     std::string stateType;
237     switch (type) {
238         case TYPE_ABSOLUTE_STILL: {
239             stateType = "absolute still";
240             break;
241         }
242         case TYPE_HORIZONTAL_POSITION: {
243             stateType = "horizontal position";
244             break;
245         }
246         case TYPE_VERTICAL_POSITION: {
247             stateType = "vertical position";
248             break;
249         }
250         case TYPE_LID_OPEN: {
251             stateType = "lid open";
252             break;
253         }
254         default: {
255             stateType = "unknown";
256             break;
257         }
258     }
259     return stateType;
260 }
261 
DumpHelpInfo(int32_t fd) const262 void DeviceStatusDumper::DumpHelpInfo(int32_t fd) const
263 {
264     dprintf(fd, "Usage:\n");
265     dprintf(fd, "      -h: dump help\n");
266     dprintf(fd, "      -s: dump the subscribers\n");
267     dprintf(fd, "      -l: dump the last 10 device status change\n");
268     dprintf(fd, "      -c: dump the current device status\n");
269     dprintf(fd, "      -o: dump the coordination status\n");
270     dprintf(fd, "      -d: dump the drag status\n");
271     dprintf(fd, "      -m, dump the macro state\n");
272 }
273 
SaveAppInfo(std::shared_ptr<AppInfo> appInfo)274 void DeviceStatusDumper::SaveAppInfo(std::shared_ptr<AppInfo> appInfo)
275 {
276     CALL_DEBUG_ENTER;
277     CHKPV(appInfo);
278     GetTimeStamp(appInfo->startTime);
279     std::set<std::shared_ptr<AppInfo>> appInfos;
280     auto iter = appInfoMap_.find(appInfo->type);
281     if (iter == appInfoMap_.end()) {
282         if (appInfos.insert(appInfo).second) {
283             auto [_, ret] = appInfoMap_.insert(std::make_pair(appInfo->type, appInfos));
284             if (!ret) {
285                 FI_HILOGW("type is duplicated");
286             }
287         }
288     } else {
289         if (!appInfoMap_[iter->first].insert(appInfo).second) {
290             FI_HILOGW("duplicated app info");
291         }
292     }
293 }
294 
RemoveAppInfo(std::shared_ptr<AppInfo> appInfo)295 void DeviceStatusDumper::RemoveAppInfo(std::shared_ptr<AppInfo> appInfo)
296 {
297     CALL_DEBUG_ENTER;
298     CHKPV(appInfo);
299     CHKPV(appInfo->callback);
300     FI_HILOGI("appInfoMap size:%{public}zu", appInfoMap_.size());
301 
302     auto appInfoSetIter = appInfoMap_.find(appInfo->type);
303     if (appInfoSetIter == appInfoMap_.end()) {
304         FI_HILOGE("not exist %{public}d type appInfo", appInfo->type);
305         return;
306     }
307     FI_HILOGI("callbacklist type:%{public}d, size:%{public}zu",
308         appInfo->type, appInfoMap_[appInfoSetIter->first].size());
309     auto iter = appInfoMap_.find(appInfo->type);
310     if (iter == appInfoMap_.end()) {
311         FI_HILOGW("Remove app info is not exists");
312         return;
313     }
314     for (const auto &item : iter->second) {
315         if (item->pid == appInfo->pid) {
316             iter->second.erase(item);
317             break;
318         }
319     }
320 }
321 
PushDeviceStatus(const Data & data)322 void DeviceStatusDumper::PushDeviceStatus(const Data& data)
323 {
324     CALL_DEBUG_ENTER;
325     std::unique_lock lock(mutex_);
326     auto record = std::make_shared<DeviceStatusRecord>();
327     GetTimeStamp(record->startTime);
328     record->data = data;
329     deviceStatusQueue_.push(record);
330     if (deviceStatusQueue_.size() > MAX_DEVICE_STATUS_SIZE) {
331         deviceStatusQueue_.pop();
332     }
333 }
334 
GetPackageName(Security::AccessToken::AccessTokenID tokenId)335 std::string DeviceStatusDumper::GetPackageName(Security::AccessToken::AccessTokenID tokenId)
336 {
337     CALL_DEBUG_ENTER;
338     std::string packageName = "unknown";
339     int32_t tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
340     switch (tokenType) {
341         case Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE: {
342             Security::AccessToken::NativeTokenInfo tokenInfo;
343             if (Security::AccessToken::AccessTokenKit::GetNativeTokenInfo(tokenId, tokenInfo) != 0) {
344                 FI_HILOGE("Get native token info fail");
345                 return packageName;
346             }
347             packageName = tokenInfo.processName;
348             break;
349         }
350         case Security::AccessToken::ATokenTypeEnum::TOKEN_HAP: {
351             Security::AccessToken::HapTokenInfo hapInfo;
352             if (Security::AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, hapInfo) != 0) {
353                 FI_HILOGE("Get hap token info fail");
354                 return packageName;
355             }
356             packageName = hapInfo.bundleName;
357             break;
358         }
359         default: {
360             FI_HILOGW("token type not match");
361             break;
362         }
363     }
364     return packageName;
365 }
366 
DumpCheckDefine(int32_t fd)367 void DeviceStatusDumper::DumpCheckDefine(int32_t fd)
368 {
369     ChkDefineOutput(fd);
370 }
371 
ChkDefineOutput(int32_t fd)372 void DeviceStatusDumper::ChkDefineOutput(int32_t fd)
373 {
374     CheckDefineOutput(fd, "Macro switch state:\n");
375 #ifdef OHOS_BUILD_ENABLE_COORDINATION
376     CheckDefineOutput(fd, "%-40s", "OHOS_BUILD_ENABLE_COORDINATION");
377 #endif // OHOS_BUILD_ENABLE_COORDINATION
378 }
379 
380 template<class ...Ts>
CheckDefineOutput(int32_t fd,const char * fmt,Ts...args)381 void DeviceStatusDumper::CheckDefineOutput(int32_t fd, const char* fmt, Ts... args)
382 {
383     CALL_DEBUG_ENTER;
384     CHKPV(fmt);
385     char buf[MAX_PACKET_BUF_SIZE] = {};
386     int32_t ret = snprintf_s(buf, MAX_PACKET_BUF_SIZE, MAX_PACKET_BUF_SIZE - 1, fmt, args...);
387     if (ret == -1) {
388         FI_HILOGE("Call snprintf_s failed, ret:%{public}d", ret);
389         return;
390     }
391     dprintf(fd, "%s", buf);
392 }
393 } // namespace DeviceStatus
394 } // namespace Msdp
395 } // namespace OHOS
396