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