1 /*
2  * Copyright (c) 2020-2021 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 "dfx_module.h"
17 #include "ace_log.h"
18 #include "ui_dump_dom_tree.h"
19 #ifdef FEATURE_ACELITE_MC_DFX_MODULE
20 #include "ui_snapshot.h"
21 #elif (FEATURE_ACELITE_LITE_DFX_MODULE == 1)
22 #ifdef __LITEOS_A__
23 #include "ability_env.h"
24 #endif
25 #include "ace_mem_base.h"
26 #include "js_fwk_common.h"
27 #include "ui_screenshot.h"
28 #endif
29 #ifdef __LITEOS_A__
30 #include "window/window.h"
31 #endif
32 
33 namespace OHOS {
34 namespace ACELite {
35 const char * const DfxModule::DOM_TREE_PATH = "dump_dom_tree.json";
36 
37 const char * const DfxModule::SCREEN_SNAP_PATH = "screensnap.bin";
38 
PreCheck(uint8_t argsNum)39 bool DfxModule::PreCheck(uint8_t argsNum)
40 {
41     if (argsNum > 1) {
42         HILOG_ERROR(HILOG_MODULE_ACE, "Dfx Module args num(%{public}d) is invalid, at most one parameter", argsNum);
43         return false;
44     }
45     return true;
46 }
47 
GetDomViewId(const JSIValue * args)48 char *DfxModule::GetDomViewId(const JSIValue *args)
49 {
50     if (args == nullptr) {
51         return nullptr;
52     }
53     return JSI::ValueToString(args[0]);
54 }
55 
IsEventInjectorRegistered(EventDataType type)56 bool DfxModule::IsEventInjectorRegistered(EventDataType type)
57 {
58     EventInjector* eventInjector = EventInjector::GetInstance();
59     if ((eventInjector == nullptr) || (!eventInjector->IsEventInjectorRegistered(type) &&
60         !eventInjector->RegisterEventInjector(type))) {
61         HILOG_ERROR(HILOG_MODULE_ACE, "register event error");
62         return false;
63     }
64 #ifdef __LITEOS_A__
65 #if ENABLE_WINDOW
66     RootView* rootView = RootView::GetInstance();
67     if (rootView == nullptr) {
68         HILOG_ERROR(HILOG_MODULE_ACE, "get root view error");
69         return false;
70     }
71     Window *window = rootView->GetBoundWindow();
72     if (window == nullptr) {
73         HILOG_ERROR(HILOG_MODULE_ACE, "set window id error");
74         return false;
75     }
76     eventInjector->SetWindowId(window->GetWindowId());
77 #endif
78 #endif
79     return true;
80 }
81 
82 #if (FEATURE_ACELITE_DFX_MODULE == 1)
Screenshot(const JSIValue thisVal,const JSIValue * args,uint8_t argsNum)83 JSIValue DfxModule::Screenshot(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
84 {
85 #ifdef FEATURE_ACELITE_MC_DFX_MODULE
86     JSIValue retVal = JSI::CreateBoolean(true);
87     if (!UISnapShot::ScreenshotToFile()) {
88         HILOG_ERROR(HILOG_MODULE_ACE, "screenshot failed");
89         JSI::ReleaseValue(retVal);
90         retVal = JSI::CreateBoolean(false);
91     }
92     return retVal;
93 #elif (FEATURE_ACELITE_LITE_DFX_MODULE == 1)
94     JSIValue retVal = JSI::CreateBoolean(true);
95 #ifdef __LITEOS_A__
96     const char * const savingPath = GetDataPath();
97 #elif defined(__linux__)
98     const char * const savingPath = "/storage/nfs";
99 #else
100     const char * const savingPath = "user/log";
101 #endif
102     char *path = RelocateResourceFilePath(savingPath, SCREEN_SNAP_PATH);
103     // uikit will deal with if path is null
104     UIScreenshot* screenshot = UIScreenshot::GetInstance();
105     if ((screenshot == nullptr) || (!screenshot->ScreenshotToFile(path))) {
106         HILOG_ERROR(HILOG_MODULE_ACE, "screenshot failed");
107         JSI::ReleaseValue(retVal);
108         retVal = JSI::CreateBoolean(false);
109     }
110     if (path != nullptr) {
111         ace_free(path);
112     }
113     return retVal;
114 #endif
115 }
116 #endif
117 
DumpDomTree(const JSIValue thisVal,const JSIValue * args,uint8_t argsNum)118 JSIValue DfxModule::DumpDomTree(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
119 {
120     JSIValue retVal = JSI::CreateBoolean(false);
121     if (!PreCheck(argsNum)) {
122         return retVal;
123     }
124     UIDumpDomTree* uIDumpDomTree = UIDumpDomTree::GetInstance();
125     char *viewId = GetDomViewId(args);
126 #if (FEATURE_ACELITE_LITE_DFX_MODULE == 1)
127 #ifdef __LITEOS_A__
128     const char * const savingPath = GetDataPath();
129 #elif defined(__linux__)
130     const char * const savingPath = "/storage/nfs";
131 #else
132     const char * const savingPath = "user/log";
133 #endif
134     char *path = RelocateResourceFilePath(savingPath, DOM_TREE_PATH);
135     // uikit will deal with if path and viewid is null
136     if ((uIDumpDomTree != nullptr) && (uIDumpDomTree->DumpDomTree(viewId, path))) {
137 #else
138     if ((uIDumpDomTree != nullptr) && (uIDumpDomTree->DumpDomTree(viewId))) {
139 #endif
140         JSI::ReleaseValue(retVal);
141         retVal = JSI::CreateBoolean(true);
142     }
143 
144 #if (FEATURE_ACELITE_LITE_DFX_MODULE == 1)
145     if (path != nullptr) {
146         ace_free(path);
147     }
148 #endif
149     JSI::ReleaseString(viewId);
150     return retVal;
151 }
152 
153 JSIValue DfxModule::DumpDomNode(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
154 {
155     UIDumpDomTree* uIDumpDomTree = UIDumpDomTree::GetInstance();
156     if (!PreCheck(argsNum) || (uIDumpDomTree == nullptr)) {
157         return JSI::CreateUndefined();
158     }
159 
160     char *viewId = GetDomViewId(args);
161     char *msg = uIDumpDomTree->DumpDomNode(viewId);
162     if (msg == nullptr) {
163         JSI::ReleaseString(viewId);
164         return JSI::CreateUndefined();
165     }
166     JSIValue retVal = JSI::CreateString(msg);
167     cJSON_free(msg); // use cjson malloc memory, use cJSON_free() instead of ace_free()
168     JSI::ReleaseString(viewId);
169     return retVal;
170 }
171 
172 JSIValue DfxModule::InjectPointEvent(const JSIValue *args, EventDataType type)
173 {
174     JSIValue retVal = JSI::CreateBoolean(true);
175     const uint8_t index = 2;
176     const uint32_t maxLen = 40;
177     // over 40 are ignored, ignore from beginning of the array
178     uint32_t len = JSI::GetArrayLength(args[0]);
179     uint32_t arrIndex = 0;
180     uint32_t realLen = (len > maxLen) ? maxLen : len;
181     DeviceData *data = (realLen > 0) ? static_cast<DeviceData *>(ace_malloc(sizeof(DeviceData) * realLen)) : nullptr;
182     if (len > maxLen) {
183         arrIndex = len - maxLen;
184     }
185     if (data == nullptr) {
186         HILOG_ERROR(HILOG_MODULE_ACE, "create device data failed");
187         JSI::ReleaseValue(retVal);
188         return JSI::CreateBoolean(false);
189     }
190 
191     for (uint16_t i = 0; arrIndex < len; i++, arrIndex++) {
192         JSIValue point = JSI::GetPropertyByIndex(args[0], arrIndex);
193         if (JSI::ValueIsUndefined(point)) {
194             HILOG_ERROR(HILOG_MODULE_ACE, "point is error");
195             ace_free(data);
196             JSI::ReleaseValue(retVal);
197             return JSI::CreateBoolean(false);
198         }
199         JSIValue point_x = JSI::GetPropertyByIndex(point, 0);
200         JSIValue point_y = JSI::GetPropertyByIndex(point, 1);
201         JSIValue state = JSI::GetPropertyByIndex(point, index);
202         data[i].point = {
203             static_cast<int16_t>(JSI::ValueToNumber(point_x)),
204             static_cast<int16_t>(JSI::ValueToNumber(point_y))
205         };
206         data[i].state = static_cast<uint16_t>(JSI::ValueToNumber(state));
207         JSI::ReleaseValueList(point_x, point_y, state, point);
208     }
209 
210     // simulate point event
211     EventInjector* eventInjector = EventInjector::GetInstance();
212     if ((eventInjector != nullptr) &&
213         (eventInjector->SetInjectEvent(data, realLen, type))) {
214         ace_free(data);
215         return retVal;
216     }
217     HILOG_ERROR(HILOG_MODULE_ACE, "simulator point event error");
218     ace_free(data);
219     JSI::ReleaseValue(retVal);
220     return JSI::CreateBoolean(false);
221 }
222 
223 JSIValue DfxModule::InjectEvent(const JSIValue thisVal, const JSIValue *args, uint8_t argsNum)
224 {
225     // pre check
226     const uint8_t num = 2;
227     if (argsNum != num) {
228         HILOG_ERROR(HILOG_MODULE_ACE, "Dfx Module args num(%{public}d) is invalid, only one parameter", argsNum);
229         return JSI::CreateBoolean(false);
230     }
231 
232     // dispatch register event
233     char *eventType = JSI::ValueToString(args[1]);
234     if (eventType == nullptr) {
235         return JSI::CreateBoolean(false);
236     }
237     if (!strcmp(eventType, "point")) {
238         JSI::ReleaseString(eventType);
239         EventDataType type = EventDataType::POINT_TYPE;
240         if (!IsEventInjectorRegistered(type)) {
241             return JSI::CreateBoolean(false);
242         }
243         return InjectPointEvent(args, type);
244     }
245     HILOG_ERROR(HILOG_MODULE_ACE, "only support point event");
246 
247     JSI::ReleaseString(eventType);
248     return JSI::CreateBoolean(false);
249 }
250 
251 void DfxModule::OnDestroy()
252 {
253     EventInjector* eventInjector = EventInjector::GetInstance();
254     // iterator remove all registered event
255     if (eventInjector != nullptr) {
256         eventInjector->UnregisterEventInjector(EventDataType::POINT_TYPE);
257         eventInjector->UnregisterEventInjector(EventDataType::OTHERS);
258     }
259 }
260 } // namespace ACELite
261 } // namespace OHOS
262