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