1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include <algorithm>
10 #include <hdf_io_service.h>
11 #include <idevmgr_hdi.h>
12 #include <iostream>
13 #include <iservmgr_hdi.h>
14 #include <osal_time.h>
15 #include <string>
16 #include <string_ex.h>
17 #include <vector>
18 
19 #define HDF_LOG_TAG hdf_dbg
20 
21 static constexpr uint32_t DATA_SIZE = 5000;
22 static constexpr uint32_t FUNC_IDX = 1;
23 static constexpr uint32_t SERVER_NAME_IDX = 3;
24 static constexpr uint32_t INTERFACE_DESC_IDX = 4;
25 static constexpr uint32_t CMD_ID_IDX = 5;
26 static constexpr uint32_t PARA_CNT_IDX = 6;
27 static constexpr uint32_t PARA_MULTIPLE = 2;
28 static constexpr uint32_t WAIT_TIME = 100;
29 static constexpr uint32_t HELP_INFO_PARA_CNT = 2;
30 static constexpr uint32_t GET_INFO_FUNC_NUMS = 5;
31 static constexpr int32_t DBG_HDI_PARA_MIN_LEN = 7;
32 static constexpr int32_t DBG_HDI_SERVICE_LOAD_IDX = 2;
33 static constexpr int32_t QUERY_INFO_PARA_CNT = 3;
34 static constexpr int32_t ALIGN_SIZE = 30;
35 static constexpr int32_t PARAM_IN_OUT_SIZE = 2;
36 static constexpr int32_t PARAM_IN_SIZE = 1;
37 static constexpr int32_t PARAM_IN_IDX = 0;
38 static constexpr int32_t PARAM_OUT_IDX = 1;
39 static constexpr const char *HELP_COMMENT =
40     " hdf_dbg menu:  \n"
41     " hdf_dbg -h   :display help information\n"
42     " hdf_dbg -q   :query all service and device information\n"
43     " hdf_dbg -q 0 :query service information of kernel space\n"
44     " hdf_dbg -q 1 :query service information of user space\n"
45     " hdf_dbg -q 2 :query device information of kernel space\n"
46     " hdf_dbg -q 3 :query device information use space\n"
47     " hdf_dbg -d   :debug hdi interface\n"
48     "   detailed usage:\n"
49     "   debug hdi interface, parameterType can be int or string now, for example:\n"
50     "     hdf_dbg -d loadFlag serviceName interfaceToken cmd parameterInCount parameterInType parameterInValue\n"
51     "     hdf_dbg -d loadFlag serviceName interfaceToken cmd parameterInCount,parameterOutCount parameterInType "
52     "parameterInValue parameterOutType\n"
53     "     detailed examples:\n"
54     "       hdf_dbg -d 1 sample_driver_service hdf.test.sampele_service 1 2 int 100 int 200\n"
55     "       hdf_dbg -d 1 sample_driver_service hdf.test.sampele_service 1 2,1 int 100 int 200 int\n"
56     "       hdf_dbg -d 0 sample_driver_service hdf.test.sampele_service 7 1 string foo\n";
57 
58 using GetInfoFunc = void (*)();
59 static void GetAllServiceUserSpace();
60 static void GetAllServiceKernelSpace();
61 static void GetAllDeviceUserSpace();
62 static void GetAllDeviceKernelSpace();
63 static void GetAllInformation();
64 
65 GetInfoFunc g_getInfoFuncs[GET_INFO_FUNC_NUMS] = {
66     GetAllServiceKernelSpace,
67     GetAllServiceUserSpace,
68     GetAllDeviceKernelSpace,
69     GetAllDeviceUserSpace,
70     GetAllInformation,
71 };
72 
73 using OHOS::MessageOption;
74 using OHOS::MessageParcel;
75 using OHOS::HDI::DeviceManager::V1_0::HdiDevHostInfo;
76 using OHOS::HDI::DeviceManager::V1_0::IDeviceManager;
77 using OHOS::HDI::ServiceManager::V1_0::HdiServiceInfo;
78 using OHOS::HDI::ServiceManager::V1_0::IServiceManager;
79 using std::cout;
80 using std::endl;
81 
82 class HdfDbg {
83 public:
84     bool loadDevice;
85     std::string serviceName;
86     std::u16string descriptor;
87     int32_t cmd;
88     int32_t inParam;
89     int32_t outParam;
90     std::vector<std::vector<std::string>> inParamVec;
91     std::vector<std::string> outParamVec;
92 };
93 
PrintHelp()94 static void PrintHelp()
95 {
96     cout << HELP_COMMENT;
97 }
98 
StrToInt(std::string tempstr)99 static int StrToInt(std::string tempstr)
100 {
101     int32_t num = GET_INFO_FUNC_NUMS;
102     if (std::all_of(tempstr.begin(), tempstr.end(), ::isdigit)) {
103         num = std::stoi(tempstr);
104     }
105     return num;
106 }
107 
SetPadAlign(std::string & name,char padChar,int32_t size)108 static void SetPadAlign(std::string &name, char padChar, int32_t size)
109 {
110     int32_t padCnt = size - static_cast<int32_t>(name.length());
111 
112     padCnt = (padCnt <= 0) ? 0 : padCnt;
113     name.append(padCnt, padChar);
114 }
115 
PrintAllServiceInfoUser(std::vector<HdiServiceInfo> & serviceInfos)116 static void PrintAllServiceInfoUser(std::vector<HdiServiceInfo> &serviceInfos)
117 {
118     uint32_t cnt = 0;
119     std::string titleName = "serviceName";
120     SetPadAlign(titleName, ' ', ALIGN_SIZE);
121 
122     cout << "display service info in user space, format:" << endl;
123     cout << titleName << ":devClass" << "\t:devId" << endl;
124 
125     for (auto &info : serviceInfos) {
126         SetPadAlign(info.serviceName, ' ', ALIGN_SIZE);
127         cout << info.serviceName << ":0x" << std::hex << info.devClass << "\t:0x" << info.devId << endl;
128         cnt++;
129     }
130 
131     cout << "total " << std::dec << cnt << " services in user space" << endl;
132 }
133 
PrintAllServiceInfoKernel(struct HdfSBuf * data,bool flag)134 static void PrintAllServiceInfoKernel(struct HdfSBuf *data, bool flag)
135 {
136     uint32_t cnt = 0;
137     std::string titleName = "serviceName";
138 
139     SetPadAlign(titleName, ' ', ALIGN_SIZE);
140     cout << "display service info in kernel space, format:" << endl;
141     cout << titleName << ":devClass" << "\t:devId" << endl;
142 
143     while (flag) {
144         const char *servName = HdfSbufReadString(data);
145         if (servName == nullptr) {
146             break;
147         }
148 
149         uint16_t devClass;
150         if (!HdfSbufReadUint16(data, &devClass)) {
151             return;
152         }
153 
154         uint32_t devId;
155         if (!HdfSbufReadUint32(data, &devId)) {
156             return;
157         }
158 
159         std::string serviceName = servName;
160         SetPadAlign(serviceName, ' ', ALIGN_SIZE);
161         cout << serviceName << ":0x" << std::hex << devClass << "\t:0x" << devId << endl;
162         cnt++;
163     }
164 
165     cout << "total " << std::dec << cnt << " services in kernel space" << endl;
166 }
167 
PrintALLDeviceInfoUser(std::vector<HdiDevHostInfo> & deviceInfos)168 static void PrintALLDeviceInfoUser(std::vector<HdiDevHostInfo> &deviceInfos)
169 {
170     cout << "display device info in user space, format:" << endl;
171     std::string titleHostName = "hostName";
172     SetPadAlign(titleHostName, ' ', ALIGN_SIZE);
173 
174     cout << titleHostName << ":hostId" << endl;
175 
176     std::string titleDevName = "deviceName";
177     std::string titleSrvName = ":serviceName";
178     SetPadAlign(titleDevName, ' ', ALIGN_SIZE);
179     SetPadAlign(titleSrvName, ' ', ALIGN_SIZE);
180 
181     cout << "\t" << titleDevName << ":deviceId  \t" << titleSrvName << endl;
182     uint32_t hostCnt = 0;
183     uint32_t devNodeCnt = 0;
184 
185     for (auto &info : deviceInfos) {
186         SetPadAlign(info.hostName, ' ', ALIGN_SIZE);
187         cout << info.hostName << ":0x" << std::hex << info.hostId << endl;
188         for (auto &dev : info.devInfo) {
189             SetPadAlign(dev.deviceName, ' ', ALIGN_SIZE);
190             SetPadAlign(dev.servName, ' ', ALIGN_SIZE);
191             cout << "\t" << dev.deviceName << ":0x" << std::hex << dev.devId << "\t:" << dev.servName << endl;
192             devNodeCnt++;
193         }
194         hostCnt++;
195     }
196 
197     cout << "total " << std::dec << hostCnt << " hosts, " << devNodeCnt << " devNodes in user space" << endl;
198 }
199 
PrintOneHostInfoKernel(struct HdfSBuf * data,uint32_t & devNodeCnt)200 static int32_t PrintOneHostInfoKernel(struct HdfSBuf *data, uint32_t &devNodeCnt)
201 {
202     const char *hostName = HdfSbufReadString(data);
203     if (hostName == nullptr) {
204         return HDF_FAILURE;
205     }
206 
207     uint32_t hostId;
208     if (!HdfSbufReadUint32(data, &hostId)) {
209         cout << "PrintOneHostInfoKernel HdfSbufReadUint32 hostId failed" << endl;
210         return HDF_FAILURE;
211     }
212 
213     std::string hostNameStr = hostName;
214     SetPadAlign(hostNameStr, ' ', ALIGN_SIZE);
215     cout << hostNameStr << ":0x" << std::hex << hostId << endl;
216 
217     uint32_t devCnt;
218     if (!HdfSbufReadUint32(data, &devCnt)) {
219         cout << "PrintOneHostInfoKernel HdfSbufReadUint32 devCnt failed" << endl;
220         return HDF_FAILURE;
221     }
222 
223     for (uint32_t i = 0; i < devCnt; i++) {
224         const char *str = HdfSbufReadString(data);
225         std::string deviceName = (str == nullptr) ? "" : str;
226         SetPadAlign(deviceName, ' ', ALIGN_SIZE);
227 
228         uint32_t devId;
229         if (!HdfSbufReadUint32(data, &devId)) {
230             cout << "PrintOneHostInfoKernel HdfSbufReadUint32 devId failed" << endl;
231             return HDF_FAILURE;
232         }
233 
234         str = HdfSbufReadString(data);
235         std::string servName = (str == nullptr) ? "" : str;
236         SetPadAlign(servName, ' ', ALIGN_SIZE);
237         cout << "\t" << deviceName << ":0x" << std::hex << devId << "\t:" << servName << endl;
238     }
239     devNodeCnt += devCnt;
240 
241     return HDF_SUCCESS;
242 }
PrintAllDeviceInfoKernel(struct HdfSBuf * data,bool flag)243 static void PrintAllDeviceInfoKernel(struct HdfSBuf *data, bool flag)
244 {
245     uint32_t hostCnt = 0;
246     uint32_t devNodeCnt = 0;
247 
248     std::string titleHostName = "hostName";
249     SetPadAlign(titleHostName, ' ', ALIGN_SIZE);
250     cout << "display device info in kernel space, format:" << endl;
251     cout << titleHostName << ":hostId" << endl;
252 
253     std::string titleDevName = "deviceName";
254     std::string titleSrvName = "serviceName";
255     SetPadAlign(titleDevName, ' ', ALIGN_SIZE);
256     SetPadAlign(titleSrvName, ' ', ALIGN_SIZE);
257     cout << "\t" << titleDevName << ":deviceId  \t:" << titleSrvName << endl;
258 
259     while (flag) {
260         if (PrintOneHostInfoKernel(data, devNodeCnt) == HDF_FAILURE) {
261             break;
262         }
263         hostCnt++;
264     }
265 
266     cout << "total " << std::dec << hostCnt << " hosts, " << devNodeCnt << " devNodes in kernel space" << endl;
267 }
268 
ParseParameterCount(int argc,char ** argv,HdfDbg & info)269 static bool ParseParameterCount(int argc, char **argv, HdfDbg &info)
270 {
271     std::string paramCount = argv[PARA_CNT_IDX];
272     std::vector<std::string> result;
273     OHOS::SplitStr(paramCount, ",", result);
274     info.inParam = 0;
275     info.outParam = 0;
276     if (result.size() == PARAM_IN_SIZE) {
277         info.inParam = StrToInt(result[PARAM_IN_IDX]);
278     } else if (result.size() == PARAM_IN_OUT_SIZE) {
279         info.inParam = StrToInt(result[PARAM_IN_IDX]);
280         info.outParam = StrToInt(result[PARAM_OUT_IDX]);
281     } else {
282         cout << "parameter count parse failed, input: " << paramCount <<
283             " it should be paramIn,paramOut or paramIn" << endl;
284         return false;
285     }
286     if ((info.inParam * PARA_MULTIPLE + info.outParam) != (argc - PARA_CNT_IDX - 1)) {
287         cout << "parameter count error, please check your input and output parameters" << endl;
288         return false;
289     }
290     return true;
291 }
292 
ParseParameterIn(int argc,char ** argv,HdfDbg & info)293 static bool ParseParameterIn(int argc, char **argv, HdfDbg &info)
294 {
295     int32_t paraTypeIdx = PARA_CNT_IDX + 1;
296     for (int32_t i = 0; i < info.inParam; i++) {
297         int32_t paraValueIdx = paraTypeIdx + 1;
298         if (strcmp(argv[paraTypeIdx], "string") != 0 && strcmp(argv[paraTypeIdx], "int") != 0) {
299             cout << "parameterType not support:" << argv[paraTypeIdx] << endl;
300             return false;
301         }
302         info.inParamVec.push_back(std::vector<std::string>());
303         info.inParamVec[i].push_back(argv[paraTypeIdx]);
304         info.inParamVec[i].push_back(argv[paraValueIdx]);
305         paraTypeIdx += PARA_MULTIPLE;
306     }
307     return true;
308 }
309 
ParseParameterOut(int argc,char ** argv,HdfDbg & info)310 static bool ParseParameterOut(int argc, char **argv, HdfDbg &info)
311 {
312     int32_t paraTypeIdx = PARA_CNT_IDX + 1 + info.inParam * PARA_MULTIPLE;
313     for (int32_t i = 0; i < info.outParam; i++) {
314         if (strcmp(argv[paraTypeIdx], "string") != 0 && strcmp(argv[paraTypeIdx], "int") != 0) {
315             cout << "parameterType not support:" << argv[paraTypeIdx] << endl;
316             return false;
317         }
318         info.outParamVec.push_back(argv[paraTypeIdx]);
319         paraTypeIdx++;
320     }
321     return true;
322 }
323 
ParseHdfDbg(int argc,char ** argv,HdfDbg & info)324 static bool ParseHdfDbg(int argc, char **argv, HdfDbg &info)
325 {
326     if (argc < DBG_HDI_PARA_MIN_LEN) {
327         return false;
328     }
329     info.loadDevice = strcmp(argv[DBG_HDI_SERVICE_LOAD_IDX], "1") == 0 ? true : false;
330     info.serviceName = argv[SERVER_NAME_IDX];
331     info.descriptor = OHOS::Str8ToStr16(argv[INTERFACE_DESC_IDX]);
332     info.cmd = StrToInt(argv[CMD_ID_IDX]);
333     if (!ParseParameterCount(argc, argv, info) || !ParseParameterIn(argc, argv, info) ||
334         !ParseParameterOut(argc, argv, info)) {
335         return false;
336     }
337     return true;
338 }
339 
InjectDebugHdi(int argc,char ** argv)340 static int32_t InjectDebugHdi(int argc, char **argv)
341 {
342     HdfDbg info;
343     if (!ParseHdfDbg(argc, argv, info)) {
344         PrintHelp();
345         return HDF_FAILURE;
346     }
347     auto servmgr = IServiceManager::Get();
348     auto devmgr = IDeviceManager::Get();
349     if (info.loadDevice) {
350         devmgr->LoadDevice(info.serviceName);
351         OsalMSleep(WAIT_TIME);
352     }
353     MessageParcel data;
354     data.WriteInterfaceToken(info.descriptor);
355     for (int32_t i = 0; i < info.inParam; i++) {
356         if (info.inParamVec[i][0] == "string") {
357             data.WriteCString(info.inParamVec[i][1].c_str());
358         } else {
359             data.WriteInt32(StrToInt(info.inParamVec[i][1]));
360         }
361     }
362     MessageParcel reply;
363     MessageOption option;
364     int32_t ret = HDF_FAILURE;
365     auto service = servmgr->GetService(info.serviceName.c_str());
366     if (service == nullptr) {
367         cout << "getService " << info.serviceName << " failed" << endl;
368         goto END;
369     }
370     ret = service->SendRequest(info.cmd, data, reply, option);
371     cout << "call service " << info.serviceName << " hdi cmd:" << info.cmd << " return:" << ret << endl;
372     for (int32_t i = 0; i < info.outParam; i++) {
373         if (info.outParamVec[i] == "string") {
374             cout << "output parameter" << i << ": parameterType is string, parameterValue is " <<
375             reply.ReadCString() << endl;
376         } else {
377             int32_t replyInt;
378             reply.ReadInt32(replyInt);
379             cout << "output parameter" << i << ": parameterType is int, parameterValue is " << replyInt << endl;
380         }
381     }
382 END:
383     if (info.loadDevice) {
384         devmgr->UnloadDevice(info.serviceName);
385     }
386     return ret;
387 }
388 
GetAllServiceUserSpace()389 static void GetAllServiceUserSpace()
390 {
391     auto servmgr = IServiceManager::Get();
392     if (servmgr == nullptr) {
393         cout << "GetAllServiceUserSpace get ServiceManager failed" << endl;
394         return;
395     }
396 
397     std::vector<HdiServiceInfo> serviceInfos;
398     (void)servmgr->ListAllService(serviceInfos);
399 
400     PrintAllServiceInfoUser(serviceInfos);
401 }
402 
GetAllServiceKernelSpace()403 static void GetAllServiceKernelSpace()
404 {
405     struct HdfSBuf *data = HdfSbufObtain(DATA_SIZE);
406     if (data == nullptr) {
407         cout << "GetAllServiceKernelSpace HdfSbufObtain failed" << endl;
408         return;
409     }
410 
411     int32_t ret = HdfListAllService(data);
412     OsalMSleep(WAIT_TIME);
413     if (ret == HDF_SUCCESS) {
414         PrintAllServiceInfoKernel(data, true);
415     } else {
416         PrintAllServiceInfoKernel(data, false);
417     }
418 
419     HdfSbufRecycle(data);
420 }
421 
GetAllDeviceUserSpace()422 static void GetAllDeviceUserSpace()
423 {
424     auto devmgr = IDeviceManager::Get();
425     if (devmgr == nullptr) {
426         cout << "GetAllDeviceUserSpace get DeviceManager failed" << endl;
427         return;
428     }
429 
430     std::vector<HdiDevHostInfo> deviceInfos;
431     (void)devmgr->ListAllDevice(deviceInfos);
432     PrintALLDeviceInfoUser(deviceInfos);
433 }
434 
GetAllDeviceKernelSpace()435 static void GetAllDeviceKernelSpace()
436 {
437     struct HdfSBuf *data = HdfSbufObtain(DATA_SIZE);
438     if (data == nullptr) {
439         cout << "GetAllDeviceKernelSpace HdfSbufObtain failed" << endl;
440         return;
441     }
442 
443     int32_t ret = HdfListAllDevice(data);
444     OsalMSleep(WAIT_TIME);
445     if (ret == HDF_SUCCESS) {
446         PrintAllDeviceInfoKernel(data, true);
447     } else {
448         PrintAllDeviceInfoKernel(data, false);
449     }
450 
451     HdfSbufRecycle(data);
452 }
453 
GetAllInformation()454 static void GetAllInformation()
455 {
456     GetAllServiceUserSpace();
457     cout << endl;
458     GetAllServiceKernelSpace();
459     cout << endl;
460     GetAllDeviceUserSpace();
461     cout << endl;
462     GetAllDeviceKernelSpace();
463 }
464 
main(int argc,char ** argv)465 int main(int argc, char **argv)
466 {
467     if (argc == 1 || (argc == HELP_INFO_PARA_CNT && strcmp(argv[FUNC_IDX], "-h") == 0)) {
468         PrintHelp();
469     } else if (argc == QUERY_INFO_PARA_CNT || argc == QUERY_INFO_PARA_CNT - 1) {
470         if (strcmp(argv[FUNC_IDX], "-q") != 0) {
471             PrintHelp();
472             return HDF_FAILURE;
473         }
474 
475         if (argc == QUERY_INFO_PARA_CNT - 1) {
476             g_getInfoFuncs[GET_INFO_FUNC_NUMS - 1]();
477             return HDF_SUCCESS;
478         }
479         std::string argvStr = argv[QUERY_INFO_PARA_CNT - 1];
480         uint32_t queryIdx = static_cast<uint32_t>(StrToInt(argvStr));
481         if (queryIdx < GET_INFO_FUNC_NUMS - 1) {
482             g_getInfoFuncs[queryIdx]();
483         } else {
484             PrintHelp();
485             return HDF_FAILURE;
486         }
487     } else if (argc > QUERY_INFO_PARA_CNT) {
488         if (strcmp(argv[FUNC_IDX], "-d") == 0) {
489             return InjectDebugHdi(argc, argv);
490         } else {
491             PrintHelp();
492             return HDF_FAILURE;
493         }
494     }
495 
496     return HDF_SUCCESS;
497 }
498