• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "platform.h"
17 
18 // v8 header
19 #include "v8.h"
20 
21 // OHOS API header
22 #include "hilog/log.h"
23 #include "hitrace_meter.h"
24 #include "init_param.h"
25 #include "jsvm_log.h"
26 #include "res_sched_client.h"
27 #include "unistd.h"
28 #ifdef ENABLE_HISYSEVENT
29 #include "hisysevent.h"
30 #endif
31 #include <dlfcn.h>
32 #include <string>
33 #include <sys/prctl.h>
34 #include <unordered_set>
35 
36 #define USE_C_API
37 namespace platform {
Abort()38 void OS::Abort()
39 {
40     std::abort();
41 }
42 
GetUid()43 uint64_t OS::GetUid()
44 {
45     return static_cast<uint64_t>(getuid());
46 }
47 
GetPid()48 uint64_t OS::GetPid()
49 {
50     return static_cast<uint64_t>(getprocpid());
51 }
52 
GetTid()53 uint64_t OS::GetTid()
54 {
55     return static_cast<uint64_t>(getproctid());
56 }
57 
58 #ifdef LOG_DOMAIN
59 #undef LOG_DOMAIN
60 #endif
61 #ifdef LOG_TAG
62 #undef LOG_TAG
63 #endif
64 
65 #define LOG_DOMAIN 0xD003900
66 #define LOG_TAG "JSVM"
67 
PrintString(LogLevel level,const char * string)68 void OS::PrintString(LogLevel level, const char* string)
69 {
70     // convert platform defined LogLevel to hilog LogLevel
71     static constexpr ::LogLevel convertArray[] = { ::LogLevel::LOG_DEBUG, ::LogLevel::LOG_INFO, ::LogLevel::LOG_WARN,
72                                                    ::LogLevel::LOG_ERROR, ::LogLevel::LOG_FATAL };
73     static_assert(sizeof(convertArray) / sizeof(::LogLevel) == static_cast<uint64_t>(OS::LogLevel::LOG_FATAL) + 1);
74 
75     HiLogPrint(LOG_APP, convertArray[static_cast<uint64_t>(level)], LOG_DOMAIN, LOG_TAG, "%{public}s", string);
76 }
77 
Print(LogLevel level,const char * format,...)78 void OS::Print(LogLevel level, const char* format, ...)
79 {
80     constexpr size_t maxStringSize = 1024;
81     char string[maxStringSize];
82     va_list arguments;
83     va_start(arguments, format);
84     int len = vsnprintf_s(string, sizeof(string), sizeof(string) - 1, format, arguments);
85     va_end(arguments);
86 
87     if (len < 0) {
88         PrintString(LogLevel::LOG_ERROR, "vsnprintf_s failed");
89         return;
90     }
91     PrintString(level, string);
92 }
93 
94 #define JSVM_HITRACE_TAG HITRACE_TAG_OHOS
95 
RunJsTrace(bool runJs)96 RunJsTrace::RunJsTrace(bool runJs) : runJs(runJs)
97 {
98     if (runJs) {
99         StartTrace(JSVM_HITRACE_TAG, "PureJS");
100     } else {
101         FinishTrace(JSVM_HITRACE_TAG);
102     }
103 }
104 
RunJsTrace(const char * name)105 RunJsTrace::RunJsTrace(const char* name) : runJs(true)
106 {
107     StartTrace(JSVM_HITRACE_TAG, name);
108 }
109 
~RunJsTrace()110 RunJsTrace::~RunJsTrace()
111 {
112     if (runJs) {
113         FinishTrace(JSVM_HITRACE_TAG);
114     } else {
115         StartTrace(JSVM_HITRACE_TAG, "PureJS");
116     }
117 }
118 
119 #ifdef USE_C_API
120 namespace ResourceSchedule {
121 namespace ResType {
122 extern "C" void ReportData(uint32_t resType,
123                            int64_t value,
124                            const std::unordered_map<std::string, std::string>& mapPayLoad);
125 
126 enum : uint32_t { RES_TYPE_REPORT_KEY_THREAD = 39 };
127 
128 enum ReportChangeStatus : int64_t { CREATE = 0, REMOVE = 1 };
129 
130 enum ThreadRole : int64_t {
131     USER_INTERACT = 0,
132     NORMAL_DISPLAY = 1,
133     IMPORTANT_DISPLAY = 2,
134     NORMAL_AUDIO = 3,
135     IMPORTANT_AUDIO = 4,
136     IMAGE_DECODE = 5
137 };
138 } // namespace ResType
139 } // namespace ResourceSchedule
140 #endif
141 
142 static bool isJitMode = true;
143 namespace ohos {
144 #define JITFORT_QUERY_ENCAPS 'E'
145 #define HM_PR_SET_JITFORT 0x6a6974
146 
147 bool ProcessBundleName(std::string& bundleName);
148 
InJitMode()149 bool InJitMode()
150 {
151     return isJitMode;
152 }
153 
HasJitfortACL()154 inline bool HasJitfortACL()
155 {
156     return (prctl(HM_PR_SET_JITFORT, JITFORT_QUERY_ENCAPS, 0) == 0);
157 }
158 
159 #ifdef USE_C_API
ReportKeyThread(ThreadRole role)160 void ReportKeyThread(ThreadRole role)
161 {
162     uint64_t uid = OS::GetUid();
163     uint64_t tid = OS::GetTid();
164     uint64_t pid = OS::GetPid();
165     std::unordered_map<std::string, std::string> payLoad = { { "uid", std::to_string(uid) },
166                                                              { "pid", std::to_string(pid) },
167                                                              { "tid", std::to_string(tid) },
168                                                              { "role", std::to_string(role) } };
169     ReportData(ResourceSchedule::ResType::RES_TYPE_REPORT_KEY_THREAD,
170                ResourceSchedule::ResType::ReportChangeStatus::CREATE, payLoad);
171 }
172 #else
ReportKeyThread(ThreadRole role)173 void ReportKeyThread(ThreadRole role)
174 {
175     static_assert(static_cast<int64_t>(ThreadRole::IMPORTANT_DISPLAY) ==
176                   static_cast<int64_t>(OHOS::ResourceSchedule::ResType::IMPORTANT_DISPLAY));
177     static_assert(static_cast<int64_t>(ThreadRole::USER_INTERACT) ==
178                   static_cast<int64_t>(OHOS::ResourceSchedule::ResType::USER_INTERACT));
179 
180     uint64_t uid = OS::GetUid();
181     uint64_t tid = OS::GetTid();
182     uint64_t pid = OS::GetPid();
183     std::unordered_map<std::string, std::string> payLoad = { { "uid", std::to_string(uid) },
184                                                              { "pid", std::to_string(pid) },
185                                                              { "tid", std::to_string(tid) },
186                                                              { "role", std::to_string(role) } };
187     OHOS::ResourceSchedule::ResSchedClient::GetInstance().ReportData(
188         OHOS::ResourceSchedule::ResType::RES_TYPE_REPORT_KEY_THREAD,
189         OHOS::ResourceSchedule::ResType::ReportChangeStatus::CREATE, payLoad);
190 }
191 #endif
192 
ReadAdvancedSecurityMode()193 bool ReadAdvancedSecurityMode()
194 {
195     void *hdl = dlopen("/system/lib64/platformsdk/libdsmm_innersdk.z.so", RTLD_LAZY);
196     if (!hdl) {
197         LOG(Error) << "[AdvancedSecurityMode]: dlopen failed";
198         return false;
199     }
200 
201     using AdvSecModeGetPtr = int32_t (*)(const char *feature, uint32_t featureLen,
202                                          const char *param, uint32_t paramLen, uint32_t *state);
203     AdvSecModeGetPtr func = reinterpret_cast<AdvSecModeGetPtr>(dlsym(hdl, "AdvancedSecurityModeGetStateByFeature"));
204     if (!func) {
205         LOG(Error) << "[AdvancedSecurityMode]: dlsym failed";
206         dlclose(hdl);
207         return false;
208     }
209 
210     const char* featureName = "RESTRICTED_JSVM_FEATURES";
211     const char* emptyParam = "{}";
212     uint32_t state = 0;
213     int32_t ret = func(featureName, strlen(featureName), emptyParam, strlen(emptyParam), &state);
214     dlclose(hdl);
215 
216     if (ret != 0) {
217         LOG(Error) << "[AdvancedSecurityMode]: AdvSecModeGetPtr failed";
218         return false;
219     }
220     return static_cast<bool>(state);
221 }
222 
SetSecurityMode()223 void SetSecurityMode()
224 {
225     constexpr size_t secArgCnt = 2;
226     if (ReadAdvancedSecurityMode() || !HasJitfortACL()) {
227         isJitMode = false;
228         int secArgc = secArgCnt;
229         constexpr bool removeFlag = false;
230         const char* secArgv[secArgCnt] = { "jsvm", "--jitless" };
231         v8::V8::SetFlagsFromCommandLine(&secArgc, const_cast<char**>(reinterpret_cast<const char**>(secArgv)),
232                                         removeFlag);
233     }
234 }
235 
236 constexpr int MAX_FILE_LENGTH = 32 * 1024 * 1024;
237 
LoadStringFromFile(const std::string & filePath,std::string & content)238 bool LoadStringFromFile(const std::string& filePath, std::string& content)
239 {
240     std::ifstream file(filePath.c_str());
241     if (!file.is_open()) {
242         return false;
243     }
244 
245     file.seekg(0, std::ios::end);
246     const long fileLength = file.tellg();
247     if (fileLength > MAX_FILE_LENGTH) {
248         return false;
249     }
250 
251     content.clear();
252     file.seekg(0, std::ios::beg);
253     std::copy(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), std::back_inserter(content));
254     return true;
255 }
256 
ProcessBundleName(std::string & bundleName)257 bool ProcessBundleName(std::string& bundleName)
258 {
259     int pid = getprocpid();
260     std::string filePath = "/proc/" + std::to_string(pid) + "/cmdline";
261     if (!LoadStringFromFile(filePath, bundleName)) {
262         return false;
263     }
264     if (bundleName.empty()) {
265         return false;
266     }
267     auto pos = bundleName.find(":");
268     if (pos != std::string::npos) {
269         bundleName = bundleName.substr(0, pos);
270     }
271     bundleName = bundleName.substr(0, strlen(bundleName.c_str()));
272     return true;
273 }
274 
WriteHisysevent()275 void WriteHisysevent()
276 {
277 #ifdef ENABLE_HISYSEVENT
278     std::string bundleName;
279     if (!ProcessBundleName(bundleName)) {
280         bundleName = "INVALID_BUNDLE_NAME";
281     }
282     HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::JSVM_RUNTIME, "APP_STATS",
283                     OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, "BUNDLE_NAME", bundleName);
284 #endif
285 }
286 } // namespace ohos
287 
288 } // namespace platform
289