• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 <chrono>
17 #include <unistd.h>
18 #include <memory>
19 #include <iostream>
20 #include <fstream>
21 #include <getopt.h>
22 #include <dirent.h>
23 #include <sys/stat.h>
24 #include <typeinfo>
25 #include <cstring>
26 #include <vector>
27 #include <functional>
28 #include <atomic>
29 #include <mutex>
30 #include <ctime>
31 #include <condition_variable>
32 #include <cmath>
33 #include <string>
34 #include <vector>
35 #include <cmath>
36 #include "ipc_transactor.h"
37 #include "system_ui_controller.h"
38 #include "input_manager.h"
39 #include "i_input_event_consumer.h"
40 #include "pointer_event.h"
41 #include "ui_driver.h"
42 #include "ui_record.h"
43 
44 using namespace std;
45 using namespace std::chrono;
46 
47 namespace OHOS::uitest {
48     const std::string HELP_MSG =
49     "   help,                                            print help messages\n"
50     "   screenCap,                                                          \n"
51     "   dumpLayout,                                                         \n"
52     "   uiRecord -record,    wirte location coordinates of events into files\n"
53     "   uiRecord -read,                    print file content to the console\n"
54     "   --version,                                print current tool version\n";
55     const std::string VERSION = "3.2.5.0";
56     struct option g_longoptions[] = {
57         {"save file in this path", required_argument, nullptr, 'p'},
58         {"dump all UI trees in json array format", no_argument, nullptr, 'I'}
59     };
60     /* *Print to the console of this shell process. */
PrintToConsole(string_view message)61     static inline void PrintToConsole(string_view message)
62     {
63         std::cout << message << std::endl;
64     }
65 
GetParam(int32_t argc,char * argv[],string_view optstring,string_view usage,map<char,string> & params)66     static int32_t GetParam(int32_t argc, char *argv[], string_view optstring, string_view usage,
67         map<char, string> &params)
68     {
69         int opt;
70         while ((opt = getopt_long(argc, argv, optstring.data(), g_longoptions, nullptr)) != -1) {
71             switch (opt) {
72                 case '?':
73                     PrintToConsole(usage);
74                     return EXIT_FAILURE;
75                 case 'i':
76                     params.insert(pair<char, string>(opt, "true"));
77                     break;
78                 default:
79                     params.insert(pair<char, string>(opt, optarg));
80                     break;
81             }
82         }
83         return EXIT_SUCCESS;
84     }
85 
DumpLayout(int32_t argc,char * argv[])86     static int32_t DumpLayout(int32_t argc, char *argv[])
87     {
88         auto ts = to_string(GetCurrentMicroseconds());
89         auto savePath = "/data/local/tmp/layout_" + ts + ".json";
90         map<char, string> params;
91         static constexpr string_view usage = "USAGE: uitestkit dumpLayout -p <path>";
92         if (GetParam(argc, argv, "p:i", usage, params) == EXIT_FAILURE) {
93             return EXIT_FAILURE;
94         }
95         auto iter = params.find('p');
96         if (iter != params.end()) {
97             savePath = iter->second;
98         }
99         ofstream fout;
100         fout.open(savePath, ios::out | ios::binary);
101         if (!fout) {
102             PrintToConsole("Error path:" + savePath);
103             return EXIT_FAILURE;
104         }
105         auto controller = make_unique<SysUiController>("sys_ui_controller");
106         if (!controller->ConnectToSysAbility()) {
107             PrintToConsole("Dump layout failed, cannot connect to AAMS");
108             fout.close();
109             return EXIT_FAILURE;
110         }
111         if (params.find('i') != params.end()) {
112             vector<pair<Window, nlohmann::json>> datas;
113             controller->GetUiHierarchy(datas);
114             auto array = nlohmann::json::array();
115             for (auto& data : datas) {
116                 array.push_back(data.second);
117             }
118             fout << array.dump();
119         } else {
120             UiController::RegisterController(move(controller), Priority::MEDIUM);
121             auto data = nlohmann::json();
122             auto driver = UiDriver();
123             auto error = ApiCallErr(NO_ERROR);
124             driver.DumpUiHierarchy(data, error);
125             if (error.code_ != NO_ERROR) {
126                 PrintToConsole("Dump layout failed: " + error.message_);
127                 fout.close();
128                 return EXIT_FAILURE;
129             }
130             fout << data.dump();
131         }
132         PrintToConsole("DumpLayout saved to:" + savePath);
133         fout.close();
134         return EXIT_SUCCESS;
135     }
136 
ScreenCap(int32_t argc,char * argv[])137     static int32_t ScreenCap(int32_t argc, char *argv[])
138     {
139         auto ts = to_string(GetCurrentMicroseconds());
140         auto savePath = "/data/local/tmp/screenCap_" + ts + ".png";
141         map<char, string> params;
142         static constexpr string_view usage = "USAGE: uitest screenCap -p <path>";
143         if (GetParam(argc, argv, "p:", usage, params) == EXIT_FAILURE) {
144             return EXIT_FAILURE;
145         }
146         auto iter = params.find('p');
147         if (iter != params.end()) {
148             savePath = iter->second;
149         }
150         auto controller = SysUiController("sys_ui_controller");
151         stringstream errorRecv;
152         if (!controller.TakeScreenCap(savePath, errorRecv)) {
153             PrintToConsole("ScreenCap failed: " + errorRecv.str());
154             return EXIT_FAILURE;
155         }
156         PrintToConsole("ScreenCap saved to " + savePath);
157         return EXIT_SUCCESS;
158     }
159 
TranslateToken(string_view raw)160     static string TranslateToken(string_view raw)
161     {
162         if (raw.find_first_of('@') != string_view::npos) {
163             return string(raw);
164         }
165         return "default";
166     }
167 
StartDaemon(string_view token)168     static int32_t StartDaemon(string_view token)
169     {
170         if (token.empty()) {
171             LOG_E("Empty transaction token");
172             return EXIT_FAILURE;
173         }
174         auto transalatedToken = TranslateToken(token);
175         if (daemon(0, 0) != 0) {
176             LOG_E("Failed to daemonize current process");
177             return EXIT_FAILURE;
178         }
179         LOG_I("Server starting up");
180         ApiTransactor apiTransactServer(true);
181         if (!apiTransactServer.InitAndConnectPeer(transalatedToken, ApiTransact)) {
182             LOG_E("Failed to initialize server");
183             return EXIT_FAILURE;
184         }
185         // set delayed UiController
186         auto controllerProvider = [](list<unique_ptr<UiController>> &receiver) {
187             auto controller = make_unique<SysUiController>("sys_ui_controller");
188             if (controller->ConnectToSysAbility()) {
189                 receiver.push_back(move(controller));
190             }
191         };
192         UiController::RegisterControllerProvider(controllerProvider);
193         mutex mtx;
194         unique_lock<mutex> lock(mtx);
195         condition_variable condVar;
196         apiTransactServer.SetDeathCallback([&condVar]() {
197             condVar.notify_one();
198         });
199         LOG_I("UiTest-daemon running, pid=%{public}d", getpid());
200         condVar.wait(lock);
201         LOG_I("Server exit");
202         apiTransactServer.Finalize();
203         _Exit(0);
204         return 0;
205     }
206 
UiRecord(int32_t argc,char * argv[])207     static int32_t UiRecord(int32_t argc, char *argv[])
208     {
209         static constexpr string_view usage = "USAGE: uitest uiRecord <read|record>";
210         if (!(argc == INDEX_THREE || argc == INDEX_FOUR)) {
211             PrintToConsole(usage);
212             return EXIT_FAILURE;
213         }
214         std::string opt = argv[TWO];
215         std::string modeOpt;
216         if (argc == INDEX_FOUR) {
217             modeOpt = argv[THREE];
218         }
219         if (opt == "record") {
220             if (!InitEventRecordFile()) {
221                 return OHOS::ERR_INVALID_VALUE;
222             }
223             auto controller = make_unique<SysUiController>("sys_ui_controller");
224             if (!controller->ConnectToSysAbility()) {
225                 PrintToConsole("Failed, cannot connect to AMMS ");
226                 return EXIT_FAILURE;
227             }
228             UiController::RegisterController(move(controller), Priority::MEDIUM);
229             RecordInitEnv(modeOpt);
230             auto callBackPtr = InputEventCallback::GetPtr();
231             if (callBackPtr == nullptr) {
232                 std::cout << "nullptr" << std::endl;
233                 return OHOS::ERR_INVALID_VALUE;
234             }
235             int32_t id1 = MMI::InputManager::GetInstance()->AddMonitor(callBackPtr);
236             if (id1 == -1) {
237                 std::cout << "Startup Failed!" << std::endl;
238                 return OHOS::ERR_INVALID_VALUE;
239             }
240             Timer timer;
241             timer.Start(TIMEINTERVAL, Timer::TimerFunc);
242             std::cout << "Started Recording Successfully..." << std::endl;
243             int flag = getc(stdin);
244             std::cout << flag << std::endl;
245             constexpr int timeToSleep = 3600;
246             sleep(timeToSleep);
247             return OHOS::ERR_OK;
248         } else if (opt == "read") {
249             EventData::ReadEventLine();
250             return OHOS::ERR_OK;
251         } else {
252             PrintToConsole(usage);
253             return EXIT_FAILURE;
254         }
255     }
256 
main(int32_t argc,char * argv[])257     extern "C" int32_t main(int32_t argc, char *argv[])
258     {
259         static constexpr string_view usage = "USAGE: uitest <help|screenCap|dumpLayout|uiRecord|--version>";
260         if ((size_t)argc < INDEX_TWO) {
261             PrintToConsole("Missing argument");
262             PrintToConsole(usage);
263             exit(EXIT_FAILURE);
264         }
265         string command(argv[1]);
266         if (command == "dumpLayout") {
267             exit(DumpLayout(argc, argv));
268         } else if (command == "start-daemon") {
269             string_view token = argc < 3 ? "" : argv[2];
270             exit(StartDaemon(token));
271         } else if (command == "screenCap") {
272             exit(ScreenCap(argc, argv));
273         } else if (command == "uiRecord") {
274             exit(UiRecord(argc, argv));
275         } else if (command == "--version") {
276             PrintToConsole(VERSION);
277             exit(EXIT_SUCCESS);
278         } else if (command == "help") {
279             PrintToConsole(HELP_MSG);
280             exit(EXIT_SUCCESS);
281         } else {
282             PrintToConsole("Illegal argument: " + command);
283             PrintToConsole(usage);
284             exit(EXIT_FAILURE);
285         }
286     }
287 }
288