1 /*
2 * Copyright (c) 2025 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 #include <csignal>
16 #include <cstddef>
17 #include <cstdlib>
18 #include <cstring>
19 #include <dlfcn.h>
20 #include <fcntl.h>
21 #include <memory>
22 #include <parameters.h>
23 #include <platform/common/rs_log.h>
24 #include <securec.h>
25 #include <string>
26 #include <sys/mman.h>
27 #include <sys/syscall.h>
28
29 #include "system/rs_system_parameters.h"
30
31 #include "platform/common/rs_system_properties.h"
32
33 namespace OHOS {
34 namespace Rosen {
35 #ifdef RS_ENABLE_RDO
36 #define MAX_PATH_LENGTH 128
37 #define MSG_LEN 64
38 constexpr const char *RDOPARAM = "persist.graphic.profiler.renderservice.rdo.enable";
39 constexpr const char *RDOINITPARAM = "persist.graphic.profiler.renderservice.rdo.init.successed";
40 static char g_codeCachePath[MAX_PATH_LENGTH] = "/system/lib64/librender_service_codeCache.so";
41 static char g_linkInfoPath[MAX_PATH_LENGTH] = "/system/etc/librender_service_linkInfo.bin";
42 static char g_binXOLoaderPath[MAX_PATH_LENGTH] = "/vendor/lib64/libbinxo_ld.so";
43 static const char *MSG_INFO = "RDO_CRASH";
44 static int rdo_pipe[2];
45 #ifndef NSIG
46 #define NSIG 64
47 #endif
48 static struct sigaction g_oldSigactionList[NSIG] = {};
49 static const int RDO_SIGCHAIN_CRASH_SIGNAL_LIST[] = {
50 SIGILL, SIGABRT, SIGBUS, SIGFPE, SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP};
51 constexpr size_t kSignalListSize = sizeof(RDO_SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(RDO_SIGCHAIN_CRASH_SIGNAL_LIST[0]);
52
SetRDOParam(const char * value)53 static void SetRDOParam(const char* value)
54 {
55 system::SetParameter(RDOPARAM, value);
56 }
57
IsRDOEnable()58 static bool IsRDOEnable()
59 {
60 std::string rdoFlagValue = system::GetParameter(RDOPARAM, "undef");
61 RS_LOGI("[RDO] Is RDO Enable: %{public}s", rdoFlagValue.c_str());
62 std::string rdoInitValue = system::GetParameter(RDOINITPARAM, "undef");
63 RS_LOGI("[RDO] Is RDO init successfully: %{public}s", rdoInitValue.c_str());
64 return (rdoFlagValue == "true" && rdoInitValue == "true");
65 }
66
ResetAndRethrowSignalIfNeed(int signo,siginfo_t * si)67 static void ResetAndRethrowSignalIfNeed(int signo, siginfo_t* si)
68 {
69 if (g_oldSigactionList[signo].sa_sigaction == nullptr) {
70 signal(signo, SIG_DFL);
71 } else if (sigaction(signo, &(g_oldSigactionList[signo]), nullptr) != 0) {
72 RS_LOGI("[RDO] Failed to reset signo(%{public}d).", signo);
73 signal(signo, SIG_DFL);
74 }
75
76 if (syscall(SYS_rt_tgsigqueueinfo, syscall(SYS_getpid), syscall(SYS_gettid), signo, si) != 0) {
77 RS_LOGI("[RDO] Failed to rethrow signo(%{public}d), errno(%{public}d).", signo, errno);
78 } else {
79 RS_LOGI("[RDO] Current process(%{public}ld) rethrow signo(%{public}d).", syscall(SYS_getpid), signo);
80 }
81 }
82
RDOSigchainHandler(int signo,siginfo_t * si,void * context)83 static void RDOSigchainHandler(int signo, siginfo_t* si, void* context)
84 {
85 int flags = fcntl(rdo_pipe[1], F_GETFD);
86 if (flags != -1) {
87 write(rdo_pipe[1], MSG_INFO, strlen(MSG_INFO));
88 close(rdo_pipe[1]);
89 ResetAndRethrowSignalIfNeed(signo, si);
90 }
91 }
92
InstallSigActionHandler(int signo,void (* SigHandler)(int,siginfo_t *,void *))93 static void InstallSigActionHandler(int signo, void (*SigHandler)(int, siginfo_t *, void *))
94 {
95 struct sigaction action;
96 memset_s(&action, sizeof(action), 0, sizeof(action));
97 sigfillset(&action.sa_mask);
98 action.sa_sigaction = SigHandler;
99 action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
100 if (sigaction(signo, &action, &(g_oldSigactionList[signo])) != 0) {
101 RS_LOGI("[RDO] Failed to register signal(%{public}d)", signo);
102 }
103 }
104
RDOInstallSignalHandler(void (* SigHandler)(int,siginfo_t *,void *))105 static void RDOInstallSignalHandler(void (*SigHandler)(int, siginfo_t *, void *))
106 {
107 for (size_t i = 0; i < kSignalListSize; i++) {
108 int32_t signo = RDO_SIGCHAIN_CRASH_SIGNAL_LIST[i];
109 InstallSigActionHandler(signo, SigHandler);
110 }
111 }
112
ProcessPipeMessage(int pipe_fd)113 static void ProcessPipeMessage(int pipe_fd)
114 {
115 char msg_buf[MSG_LEN];
116 memset_s(msg_buf, sizeof(msg_buf), 0, sizeof(msg_buf));
117 if (read(pipe_fd, msg_buf, MSG_LEN) > 0) {
118 RS_LOGI("[RDO] child process received message %{public}s", msg_buf);
119 if (strcmp(msg_buf, MSG_INFO) == 0) {
120 SetRDOParam("false");
121 RS_LOGI("[RDO] RDO disable");
122 }
123 }
124 close(pipe_fd);
125 RS_LOGI("[RDO] RDO child pipe closed");
126 }
127
HelperThreadforBinXO(void * arg)128 void* HelperThreadforBinXO(void* arg)
129 {
130 // For feature RDO:
131 // step1: dlopen libbinxo_ld.so
132 // step2: use func in libbinxo_ld.so to read linkinfo from librs_linkInfo.bin
133 // step3: use func in libbinxo_ld.so to load librs_codeCache.so
134 // step4: use func in libbinxo_ld.so to modify target so plt to enable rdo
135 RS_LOGI("[RDO] Start RDO");
136
137 if (!IsRDOEnable()) {
138 RS_LOGI("[RDO] RDO is not enabled");
139 return nullptr;
140 }
141 system::SetParameter(RDOINITPARAM, "false");
142
143 if (pipe(rdo_pipe) == -1) {
144 RS_LOGI("[RDO] pipe alloc error");
145 return nullptr;
146 }
147 RDOInstallSignalHandler(RDOSigchainHandler);
148 RS_LOGI("[RDO] RDOInstallSignalHandler true");
149 char canonicalPath[PATH_MAX] = { 0 };
150 if (realpath(g_binXOLoaderPath, canonicalPath) == nullptr) {
151 RS_LOGI("[RDO] Failed to canonicalize path");
152 close(rdo_pipe[0]);
153 return nullptr;
154 }
155 void* handle = dlopen(canonicalPath, RTLD_NOW);
156 if (!handle) {
157 RS_LOGI("[RDO] dlopen libbinxo_ld.so failed");
158 close(rdo_pipe[0]);
159 return nullptr;
160 }
161
162 void (*readInfo)(const char *) =
163 reinterpret_cast<void (*)(const char *)>(dlsym(handle, "_ZN11BinXOLoader12ReadLinkInfoEPc"));
164 void (*loadCC)(const char *) =
165 reinterpret_cast<void (*)(const char *)>(dlsym(handle, "_ZN11BinXOLoader13LoadCodeCacheEPc"));
166 void (*linkAll)() = reinterpret_cast<void (*)()>(dlsym(handle, "_ZN11BinXOLoader7LinkAllEv"));
167
168 if (!readInfo || !loadCC || !linkAll) {
169 RS_LOGI("[RDO] Failed to load rdo function");
170 dlclose(handle);
171 close(rdo_pipe[0]);
172 return nullptr;
173 }
174 // Read linkinfo from librs_linkInfo.bin
175 readInfo(g_linkInfoPath);
176 // Load librender_service_codeCache.so
177 loadCC(g_codeCachePath);
178 // Link all to enable rdo
179 linkAll();
180
181 dlclose(handle);
182
183 system::SetParameter(RDOINITPARAM, "true");
184
185 RS_LOGI("[RDO] RDO finish, wait msg");
186 ProcessPipeMessage(rdo_pipe[0]);
187
188 return nullptr;
189 }
190
EnableRSCodeCache()191 __attribute__((visibility("default"))) int32_t EnableRSCodeCache()
192 {
193 // Create a helper thread to load modifications for feature RDO.
194 pthread_t id = 0;
195 int ret = pthread_create(&id, nullptr, HelperThreadforBinXO, nullptr);
196 if (ret != 0) {
197 RS_LOGE("[RDO] pthread_create failed with error code %{public}d", ret);
198 }
199 pthread_setname_np(id, "binxo_helper_thread");
200 pthread_detach(id);
201 return ret;
202 }
203 #endif
204 } // namespace Rosen
205 } // namespace OHOS