• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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