• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "js_app_context.h"
17 #include "ace_event_error_code.h"
18 #include "ace_log.h"
19 #if (defined(__LINUX__) || defined(__LITEOS_A__))
20 #include "ace_ability.h"
21 #endif
22 #if (FEATURE_API_VERSION == 1)
23 #include "bundle_manager.h"
24 #endif // FEATURE_API_VERSION
25 #include "component_factory.h"
26 #include "component_utils.h"
27 #include "fatal_handler.h"
28 #include "js_app_environment.h"
29 #include "js_profiler.h"
30 #include "platform_adapter.h"
31 #include "product_adapter.h"
32 #include "securec.h"
33 #include "string_util.h"
34 #include "task_manager.h"
35 #include "ui_view_group.h"
36 #if (OHOS_ACELITE_PRODUCT_WATCH != 1)
37 #include "ability_env.h"
38 #endif
39 
40 namespace OHOS {
41 namespace ACELite {
42 constexpr char URI_PREFIX_DATA[] = "internal://app";
43 constexpr uint8_t URI_PREFIX_DATA_LENGTH = 14;
ClearContext()44 void JsAppContext::ClearContext()
45 {
46     // reset current ability path and uuid
47     ReleaseAbilityInfo();
48 }
49 
50 // check byte code file snapshot version is OK with the current
CheckSnapshotVersion(const char * bcFileContent,uint32_t contentLength) const51 void JsAppContext::CheckSnapshotVersion(const char *bcFileContent, uint32_t contentLength) const
52 {
53     // this is part of engine struct definations
54     typedef struct {
55         uint32_t magic; // four byte magic number
56         uint32_t version; // version number
57     } JerrySnapshotHeaderT;
58     if ((bcFileContent == nullptr) || (contentLength == 0) || (contentLength <= sizeof(JerrySnapshotHeaderT))) {
59         return;
60     }
61     const uint8_t *snapshotData = reinterpret_cast<const uint8_t *>(bcFileContent);
62     const JerrySnapshotHeaderT *headerP = reinterpret_cast<const JerrySnapshotHeaderT *>(snapshotData);
63     // JERRY_SNAPSHOT_VERSION is defined in jerryscript-snapshot.h
64     if (headerP->version != JERRY_SNAPSHOT_VERSION) {
65         HILOG_ERROR(HILOG_MODULE_ACE, "invalid snapshot version[%{public}d]", headerP->version);
66     }
67 }
68 
69 /**
70  * return value should be released by caller when it's not used
71  */
Eval(char * fullPath,size_t fullPathLength,bool isAppEval) const72 jerry_value_t JsAppContext::Eval(char *fullPath, size_t fullPathLength, bool isAppEval) const
73 {
74     if ((fullPath == nullptr) || (fullPathLength == 0)) {
75         HILOG_ERROR(HILOG_MODULE_ACE, "Failed to eval js code cause by empty JavaScript script.");
76         ACE_ERROR_CODE_PRINT(EXCE_ACE_ROUTER_REPLACE_FAILED, EXCE_ACE_PAGE_INDEX_MISSING);
77         return UNDEFINED;
78     }
79 
80     uint32_t contentLength = 0;
81     START_TRACING(PAGE_CODE_LOAD);
82     bool isSnapshotMode = JsAppEnvironment::GetInstance()->IsSnapshotMode();
83     char *jsCode = EvaluateFile(isSnapshotMode, contentLength, fullPath, fullPathLength);
84     STOP_TRACING();
85     if ((jsCode == nullptr) || (contentLength > FILE_CONTENT_LENGTH_MAX)) {
86         HILOG_ERROR(HILOG_MODULE_ACE, "empty js file or length is incorrect, eval user code failed");
87         ACE_ERROR_CODE_PRINT(EXCE_ACE_ROUTER_REPLACE_FAILED, EXCE_ACE_PAGE_FILE_READ_FAILED);
88         ACE_FREE(jsCode);
89         return UNDEFINED;
90     }
91 
92     START_TRACING(PAGE_CODE_EVAL);
93     jerry_value_t viewModel = UNDEFINED;
94     if (isSnapshotMode) {
95         CheckSnapshotVersion(jsCode, contentLength);
96         const uint32_t *snapshotContent = reinterpret_cast<const uint32_t *>(jsCode);
97         viewModel = jerry_exec_snapshot(snapshotContent, contentLength, 0, 1);
98     } else {
99         const jerry_char_t *jsScript = reinterpret_cast<const jerry_char_t *>(jsCode);
100         jerry_value_t retValue = jerry_parse(reinterpret_cast<const jerry_char_t *>(fullPath), fullPathLength,
101                                              jsScript, contentLength, JERRY_PARSE_NO_OPTS);
102         if (jerry_value_is_error(retValue)) {
103             ACE_ERROR_CODE_PRINT(EXCE_ACE_ROUTER_REPLACE_FAILED, EXCE_ACE_PAGE_JS_EVAL_FAILED);
104             PrintErrorMessage(retValue);
105             // free js code buffer
106             ace_free(jsCode);
107             jsCode = nullptr;
108             jerry_release_value(retValue);
109             STOP_TRACING();
110             return UNDEFINED;
111         }
112         viewModel = jerry_run(retValue);
113         jerry_release_value(retValue);
114     }
115 
116     STOP_TRACING();
117     // free js code buffer
118     ace_free(jsCode);
119     jsCode = nullptr;
120 
121     if (jerry_value_is_error(viewModel)) {
122         ACE_ERROR_CODE_PRINT(EXCE_ACE_ROUTER_REPLACE_FAILED, EXCE_ACE_PAGE_JS_EVAL_FAILED);
123         PrintErrorMessage(viewModel);
124         jerry_release_value(viewModel);
125         return UNDEFINED;
126     }
127 
128     SetGlobalNamedProperty(isAppEval, viewModel);
129     return viewModel;
130 }
131 
EvaluateFile(bool & isSnapshotMode,uint32_t & outLength,char * fullPath,size_t fullPathLength) const132 char *JsAppContext::EvaluateFile(bool &isSnapshotMode,
133                                  uint32_t &outLength,
134                                  char *fullPath,
135                                  size_t fullPathLength) const
136 {
137     if (fullPath == nullptr || fullPathLength == 0) {
138         return nullptr;
139     }
140     const uint8_t fileSuffixLength = 3; // file suffix is fixed, .js or .bc
141     size_t filePathLen = strlen(fullPath);
142     if ((filePathLen == 0) || (filePathLen != fullPathLength) || (fullPathLength < fileSuffixLength)) {
143         return nullptr;
144     }
145     outLength = 0;
146     char *jsCode = ReadFile(fullPath, outLength, isSnapshotMode);
147     if ((jsCode != nullptr) && (outLength <= FILE_CONTENT_LENGTH_MAX)) {
148         // read successfully
149         return jsCode;
150     }
151     // make sure the memory is freeed
152     ACE_FREE(jsCode);
153 
154     const char * const anotherSuffx = isSnapshotMode ? ".js" : ".bc";
155     // change file suffix to another mode file
156     if (strcpy_s((fullPath + (fullPathLength - fileSuffixLength)), (fileSuffixLength + 1), anotherSuffx) != EOK) {
157         return nullptr;
158     }
159     // snapshot mode changed to another
160     isSnapshotMode = !isSnapshotMode;
161     HILOG_ERROR(HILOG_MODULE_ACE, "JS mode changed unexpected [%{public}d]", isSnapshotMode);
162     jsCode = ReadFile(fullPath, outLength, isSnapshotMode);
163     return jsCode;
164 }
165 
SetGlobalNamedProperty(bool isAppEval,jerry_value_t viewModel) const166 void JsAppContext::SetGlobalNamedProperty(bool isAppEval, jerry_value_t viewModel) const
167 {
168     jerry_value_t globalObject = jerry_get_global_object();
169     if (isAppEval) {
170         JerrySetNamedProperty(globalObject, ATTR_APP, viewModel);
171     } else {
172         JerrySetNamedProperty(globalObject, ATTR_ROOT, viewModel);
173     }
174     jerry_release_value(globalObject);
175 }
176 
Render(jerry_value_t viewModel) const177 jerry_value_t JsAppContext::Render(jerry_value_t viewModel) const
178 {
179     if (jerry_value_is_error(viewModel)) {
180         HILOG_ERROR(HILOG_MODULE_ACE, "Failed to render app cause by render error.");
181         return UNDEFINED;
182     }
183 
184     if (jerry_value_is_undefined(viewModel)) {
185         HILOG_ERROR(HILOG_MODULE_ACE, "Nothing to render as it is undefined.");
186         return UNDEFINED;
187     }
188 
189     jerry_value_t renderFunction = jerryx_get_property_str(viewModel, ATTR_RENDER);
190     if (jerry_value_is_undefined(renderFunction)) {
191         ACE_ERROR_CODE_PRINT(EXCE_ACE_ROUTER_REPLACE_FAILED, EXCE_ACE_PAGE_NO_RENDER_FUNC);
192         return UNDEFINED;
193     }
194     jerry_value_t nativeElement = CallJSFunction(renderFunction, viewModel, nullptr, 0);
195     if (jerry_value_is_undefined(nativeElement)) {
196         ACE_ERROR_CODE_PRINT(EXCE_ACE_ROUTER_REPLACE_FAILED, EXCE_ACE_PAGE_RENDER_FAILED);
197     }
198     jerry_release_value(renderFunction);
199     return nativeElement;
200 }
201 
TerminateAbility() const202 void JsAppContext::TerminateAbility() const
203 {
204     if (currentToken_ == 0) {
205         // if no running js ability, drop
206         return;
207     }
208     FatalHandler::GetInstance().SetExitingFlag(true);
209     Terminate(currentToken_);
210 }
211 
SetCurrentAbilityInfo(const char * const abilityPath,const char * const bundleName,uint16_t token)212 void JsAppContext::SetCurrentAbilityInfo(const char * const abilityPath, const char * const bundleName, uint16_t token)
213 {
214     // release old first
215     ReleaseAbilityInfo();
216 
217     if (abilityPath != nullptr) {
218         size_t abilityPathLen = strlen(abilityPath);
219         if ((abilityPathLen > 0) && (abilityPathLen < PATH_LENGTH_MAX)) {
220             currentAbilityPath_ = static_cast<char *>(ace_malloc(abilityPathLen + 1));
221             if (currentAbilityPath_ == nullptr) {
222                 HILOG_ERROR(HILOG_MODULE_ACE, "malloc buffer for current ability path failed");
223                 return;
224             }
225             if (memcpy_s(currentAbilityPath_, abilityPathLen, abilityPath, abilityPathLen) != 0) {
226                 ace_free(currentAbilityPath_);
227                 currentAbilityPath_ = nullptr;
228                 return;
229             }
230             currentAbilityPath_[abilityPathLen] = 0;
231         }
232     }
233 
234     if (bundleName != nullptr) {
235         size_t bundleNameLen = strlen(bundleName);
236         if ((bundleNameLen > 0) && (bundleNameLen < NAME_LENGTH_MAX)) {
237             currentBundleName_ = static_cast<char *>(ace_malloc(bundleNameLen + 1));
238             if (currentBundleName_ == nullptr) {
239                 HILOG_ERROR(HILOG_MODULE_ACE, "malloc buffer for current uuid failed");
240                 return;
241             }
242             if (memcpy_s(currentBundleName_, bundleNameLen, bundleName, bundleNameLen) != 0) {
243                 ace_free(currentAbilityPath_);
244                 currentAbilityPath_ = nullptr;
245                 ace_free(currentBundleName_);
246                 currentBundleName_ = nullptr;
247                 return;
248             }
249             currentBundleName_[bundleNameLen] = 0;
250         }
251     }
252 
253     currentToken_ = token;
254 }
255 
SetCurrentJsPath(const char * const jsPath)256 void JsAppContext::SetCurrentJsPath(const char * const jsPath)
257 {
258     // release old first
259     if (currentJsPath_) {
260         ace_free(currentJsPath_);
261         currentJsPath_ = nullptr;
262     }
263 
264     if (jsPath != nullptr) {
265         size_t jsPathLen = strlen(jsPath);
266         if ((jsPathLen > 0) && (jsPathLen < PATH_LENGTH_MAX)) {
267             currentJsPath_ = static_cast<char *>(ace_malloc(jsPathLen + 1));
268             if (currentJsPath_ == nullptr) {
269                 HILOG_ERROR(HILOG_MODULE_ACE, "malloc buffer for current js path failed");
270                 return;
271             }
272             if (memcpy_s(currentJsPath_, jsPathLen, jsPath, jsPathLen) != 0) {
273                 ace_free(currentJsPath_);
274                 currentJsPath_ = nullptr;
275                 return;
276             }
277             currentJsPath_[jsPathLen] = '\0';
278         }
279     }
280 }
281 
ReleaseAbilityInfo()282 void JsAppContext::ReleaseAbilityInfo()
283 {
284     if (currentBundleName_) {
285         ace_free(currentBundleName_);
286         currentBundleName_ = nullptr;
287     }
288 
289     if (currentAbilityPath_) {
290         ace_free(currentAbilityPath_);
291         currentAbilityPath_ = nullptr;
292     }
293 
294     if (currentJsPath_) {
295         ace_free(currentJsPath_);
296         currentJsPath_ = nullptr;
297     }
298 }
299 
GetResourcePath(const char * uri) const300 char *JsAppContext::GetResourcePath(const char *uri) const
301 {
302     if (uri == nullptr) {
303         HILOG_ERROR(HILOG_MODULE_ACE, "uri is null.");
304         return nullptr;
305     }
306     size_t size = strlen(uri);
307     if (size == 0 || size > NAME_LENGTH_MAX) {
308         HILOG_ERROR(HILOG_MODULE_ACE, "uri is empty or too long.");
309         return nullptr;
310     }
311     if (StringUtil::StartsWith(uri, URI_PREFIX_DATA)) {
312         char *path = StringUtil::Slice(uri, URI_PREFIX_DATA_LENGTH);
313         if (path == nullptr) {
314             HILOG_ERROR(HILOG_MODULE_ACE, "fail to get resource path.");
315             return nullptr;
316         }
317 #if (OHOS_ACELITE_PRODUCT_WATCH == 1)
318         // no GetDataPath API provided on watch, contact the path by the product configuration insteadly
319         char *relocatedPath = ProcessResourcePathByConfiguration(size, path);
320 #else
321         const char *dataPath = GetDataPath();
322         if (dataPath == nullptr || strlen(dataPath) == 0) {
323             dataPath = currentBundleName_;
324         }
325         char *relocatedPath = RelocateResourceFilePath(dataPath, path);
326 #endif
327         ACE_FREE(path);
328         return relocatedPath;
329     }
330     return RelocateResourceFilePath(currentAbilityPath_, uri);
331 }
332 
ProcessResourcePathByConfiguration(size_t origUriLength,const char * slicedFilePath) const333 char *JsAppContext::ProcessResourcePathByConfiguration(size_t origUriLength, const char *slicedFilePath) const
334 {
335     const char *appDataRoot = ProductAdapter::GetPrivateDataRootPath();
336     if (appDataRoot == nullptr || origUriLength == 0 || slicedFilePath == nullptr) {
337         return nullptr;
338     }
339     size_t rootPathLen = strlen(appDataRoot);
340     if (rootPathLen == 0) {
341         return nullptr;
342     }
343     size_t dataPathSize = rootPathLen + strlen(currentBundleName_) + origUriLength - URI_PREFIX_DATA_LENGTH + 1;
344     char *dataPath = StringUtil::Malloc(dataPathSize);
345     if (dataPath == nullptr) {
346         HILOG_ERROR(HILOG_MODULE_ACE, "fail to malloc data path buffer.");
347         return nullptr;
348     }
349     const char *fmtStr = "%s%s";
350     if (appDataRoot[rootPathLen - 1] != RESOURCE_SEPARATOR) {
351         fmtStr = "%s/%s";
352     }
353     if (sprintf_s(dataPath, dataPathSize + 1, fmtStr, appDataRoot, currentBundleName_) < 0) {
354         HILOG_ERROR(HILOG_MODULE_ACE, "fail to get resource path.");
355         ACE_FREE(dataPath);
356         return nullptr;
357     }
358     char *relocatedPath = RelocateResourceFilePath(dataPath, slicedFilePath);
359     ACE_FREE(dataPath);
360     return relocatedPath;
361 }
362 
LoadApiVersion()363 void JsAppContext::LoadApiVersion()
364 {
365 #if (FEATURE_API_VERSION == 1)
366     BundleInfo bundle = {0};
367     uint8_t retCode = GetBundleInfo(currentBundleName_, false, &bundle);
368     if (retCode != 0) {
369         HILOG_ERROR(HILOG_MODULE_ACE, "fail to get api version.");
370         return;
371     }
372     compatibleApi_ = bundle.compatibleApi;
373     targetApi_ = bundle.targetApi;
374 #else
375     const int32_t currentApiVersion = 6;
376     compatibleApi_ = currentApiVersion;
377     targetApi_ = currentApiVersion;
378 #endif
379 }
380 
GetCompatibleApi() const381 int32_t JsAppContext::GetCompatibleApi() const
382 {
383     return compatibleApi_;
384 }
385 
SetCompatibleApi(int32_t compatibleApi)386 void JsAppContext::SetCompatibleApi(int32_t compatibleApi)
387 {
388     compatibleApi_ = compatibleApi;
389 }
390 
GetTargetApi() const391 int32_t JsAppContext::GetTargetApi() const
392 {
393     return targetApi_;
394 }
395 
SetTargetApi(int32_t targetApi)396 void JsAppContext::SetTargetApi(int32_t targetApi)
397 {
398     targetApi_ = targetApi;
399 }
400 } // namespace ACELite
401 } // namespace OHOS
402