1 /*
2 * Copyright (C) 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 "ipc_workthread.h"
17
18 #include <cmath>
19 #include <cstddef>
20 #include <memory>
21 #include <pthread.h>
22 #include <sys/prctl.h>
23 #include <sys/syscall.h>
24 #include <unistd.h>
25
26 #include "hilog/log_cpp.h"
27 #include "iosfwd"
28 #include "ipc_debug.h"
29 #include "ipc_process_skeleton.h"
30 #include "ipc_thread_skeleton.h"
31 #include "iremote_invoker.h"
32 #include "process_skeleton.h"
33 #include "string"
34 #include "type_traits"
35 #include "unistd.h"
36
37 namespace OHOS {
38 #ifdef CONFIG_IPC_SINGLE
39 namespace IPC_SINGLE {
40 #endif
41
42 static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC_COMMON, "IPCWorkThread" };
43
44 struct IPCWorkThreadParam {
45 int proto;
46 int policy;
47 int index;
48 };
49
IPCWorkThread(std::string threadName)50 IPCWorkThread::IPCWorkThread(std::string threadName) : threadName_(std::move(threadName)) {}
51
~IPCWorkThread()52 IPCWorkThread::~IPCWorkThread()
53 {
54 StopWorkThread();
55 }
56
MakeBasicThreadName(int proto,int threadIndex)57 std::string IPCWorkThread::MakeBasicThreadName(int proto, int threadIndex)
58 {
59 if (proto == IRemoteObject::IF_PROT_DATABUS) {
60 return "OS_RPC_" + std::to_string(threadIndex);
61 } else {
62 return "OS_IPC_" + std::to_string(threadIndex);
63 }
64 }
65
JoinThread(int proto,int policy)66 void IPCWorkThread::JoinThread(int proto, int policy)
67 {
68 IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(proto);
69 if (invoker != nullptr) {
70 switch (policy) {
71 case SPAWN_PASSIVE:
72 invoker->JoinThread(false);
73 break;
74 case SPAWN_ACTIVE:
75 invoker->JoinThread(true);
76 break;
77 case PROCESS_PASSIVE:
78 invoker->JoinProcessThread(false);
79 break;
80 case PROCESS_ACTIVE:
81 invoker->JoinProcessThread(true);
82 break;
83 default:
84 ZLOGE(LOG_LABEL, "invalid policy:%{public}d", policy);
85 break;
86 }
87 }
88 }
89
ThreadHandler(void * args)90 void *IPCWorkThread::ThreadHandler(void *args)
91 {
92 auto param = (IPCWorkThreadParam *)args;
93 if (param == nullptr) {
94 return nullptr;
95 }
96
97 (void)IPCThreadSkeleton::SetThreadType(ThreadType::IPC_THREAD);
98 ProcessSkeleton *process = ProcessSkeleton::GetInstance();
99 if (process == nullptr) {
100 ZLOGE(LOG_LABEL, "get ProcessSkeleton object failed");
101 delete param;
102 return nullptr;
103 }
104
105 if (process->GetThreadStopFlag()) {
106 ZLOGW(LOG_LABEL, "the stop flag is true, thread start exit");
107 delete param;
108 return nullptr;
109 }
110
111 IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(param->proto);
112 std::string basicName = MakeBasicThreadName(param->proto, param->index);
113 std::string threadName = basicName + "_" + std::to_string(syscall(SYS_gettid));
114 int32_t ret = prctl(PR_SET_NAME, threadName.c_str());
115 if (ret != 0) {
116 ZLOGE(LOG_LABEL, "set thread name:%{public}s fail, ret:%{public}d", threadName.c_str(), ret);
117 } else {
118 ZLOGI(LOG_LABEL, "proto:%{public}d policy:%{public}d name:%{public}s invoker:%{public}u", param->proto,
119 param->policy, threadName.c_str(), ProcessSkeleton::ConvertAddr(invoker));
120 }
121 IPCThreadSkeleton::SaveThreadName(threadName);
122
123 JoinThread(param->proto, param->policy);
124
125 IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent();
126 if (current != nullptr) {
127 current->OnThreadTerminated(basicName);
128 }
129 ZLOGI(LOG_LABEL, "exit, proto:%{public}d policy:%{public}d name:%{public}s invoker:%{public}u", param->proto,
130 param->policy, threadName.c_str(), ProcessSkeleton::ConvertAddr(invoker));
131 delete param;
132 return nullptr;
133 }
134
StopWorkThread()135 void IPCWorkThread::StopWorkThread()
136 {
137 IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(proto_);
138 if (invoker != nullptr) {
139 invoker->StopWorkThread();
140 }
141 }
142
Start(int policy,int proto,int threadIndex)143 void IPCWorkThread::Start(int policy, int proto, int threadIndex)
144 {
145 ProcessSkeleton *process = ProcessSkeleton::GetInstance();
146 if (process == nullptr) {
147 ZLOGE(LOG_LABEL, "get ProcessSkeleton object failed");
148 return;
149 }
150
151 if (process->GetThreadStopFlag()) {
152 ZLOGW(LOG_LABEL, "the stop flag is true, can not create other thread");
153 return;
154 }
155
156 auto param = new (std::nothrow) IPCWorkThreadParam();
157 if (param == nullptr) {
158 ZLOGE(LOG_LABEL, "create IPCWorkThreadParam failed");
159 return;
160 }
161
162 policy_ = policy;
163 proto_ = proto;
164 param->policy = policy;
165 param->proto = proto;
166 param->index = threadIndex;
167 pthread_t threadId;
168
169 int ret = pthread_create(&threadId, NULL, &IPCWorkThread::ThreadHandler, param);
170 if (ret != 0) {
171 ZLOGE(LOG_LABEL, "create thread failed, ret:%{public}d", ret);
172 delete param;
173 return;
174 }
175 process->IncreaseThreadCount();
176 ZLOGD(LOG_LABEL, "create thread, policy:%{public}d proto:%{public}d", policy, proto);
177 if (pthread_detach(threadId) != 0) {
178 ZLOGE(LOG_LABEL, "detach error");
179 }
180 }
181 #ifdef CONFIG_IPC_SINGLE
182 } // namespace IPC_SINGLE
183 #endif
184 } // namespace OHOS
185