1 /*
2 * Copyright (C) 2022-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 "process_skeleton.h"
17
18 #include <cinttypes>
19 #include <unistd.h>
20
21 #include "binder_connector.h"
22 #include "check_instance_exit.h"
23 #include "ipc_debug.h"
24 #include "log_tags.h"
25 #include "securec.h"
26 #include "string_ex.h"
27
28 namespace OHOS {
29 static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC_COMMON, "ProcessSkeleton" };
30 static constexpr int PRINT_ERR_CNT = 100;
31
32 #ifdef __aarch64__
33 static constexpr uint32_t IPC_OBJECT_MASK = 0xffffffff;
34 #else
35 static constexpr uint32_t IPC_OBJECT_MASK = 0xffffff;
36 #endif
37
38 ProcessSkeleton* ProcessSkeleton::instance_ = nullptr;
39 std::mutex ProcessSkeleton::mutex_;
40 ProcessSkeleton::DestroyInstance ProcessSkeleton::destroyInstance_;
41 std::atomic<bool> ProcessSkeleton::exitFlag_ = false;
42
GetInstance()43 ProcessSkeleton* ProcessSkeleton::GetInstance()
44 {
45 if ((instance_ == nullptr) && !exitFlag_) {
46 std::lock_guard<std::mutex> lockGuard(mutex_);
47 if ((instance_ == nullptr) && !exitFlag_) {
48 instance_ = new (std::nothrow) ProcessSkeleton();
49 if (instance_ == nullptr) {
50 ZLOGE(LOG_LABEL, "create ProcessSkeleton object failed");
51 return nullptr;
52 }
53 }
54 }
55 return instance_;
56 }
57
~ProcessSkeleton()58 ProcessSkeleton::~ProcessSkeleton()
59 {
60 ZLOGI(LOG_LABEL, "enter");
61 std::lock_guard<std::mutex> lockGuard(mutex_);
62 exitFlag_ = true;
63 {
64 std::unique_lock<std::shared_mutex> objLock(objMutex_);
65 objects_.clear();
66 isContainStub_.clear();
67 }
68 {
69 std::unique_lock<std::shared_mutex> validObjLock(validObjectMutex_);
70 validObjectRecord_.clear();
71 }
72 {
73 std::unique_lock<std::shared_mutex> invokerProcLock(invokerProcMutex_);
74 invokerProcInfo_.clear();
75 }
76 }
77
GetRegistryObject()78 sptr<IRemoteObject> ProcessSkeleton::GetRegistryObject()
79 {
80 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, nullptr);
81 std::lock_guard<std::mutex> lockGuard(mutex_);
82 return registryObject_;
83 }
84
SetRegistryObject(sptr<IRemoteObject> & object)85 void ProcessSkeleton::SetRegistryObject(sptr<IRemoteObject> &object)
86 {
87 CHECK_INSTANCE_EXIT(exitFlag_);
88 std::lock_guard<std::mutex> lockGuard(mutex_);
89 registryObject_ = object;
90 }
91
SetSamgrFlag(bool flag)92 void ProcessSkeleton::SetSamgrFlag(bool flag)
93 {
94 isSamgr_ = flag;
95 }
96
GetSamgrFlag()97 bool ProcessSkeleton::GetSamgrFlag()
98 {
99 return isSamgr_;
100 }
101
IsContainsObject(IRemoteObject * object)102 bool ProcessSkeleton::IsContainsObject(IRemoteObject *object)
103 {
104 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
105 if (object == nullptr) {
106 return false;
107 }
108 // check whether it is a valid IPCObjectStub object.
109 std::shared_lock<std::shared_mutex> lockGuard(objMutex_);
110 auto it = isContainStub_.find(object);
111 if (it != isContainStub_.end()) {
112 return it->second;
113 }
114
115 return false;
116 }
117
DetachObject(IRemoteObject * object,const std::u16string & descriptor)118 bool ProcessSkeleton::DetachObject(IRemoteObject *object, const std::u16string &descriptor)
119 {
120 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
121 std::unique_lock<std::shared_mutex> lockGuard(objMutex_);
122 (void)isContainStub_.erase(object);
123
124 // This handle may have already been replaced with a new IPCObjectProxy,
125 // if someone failed the AttemptIncStrong.
126 auto iterator = objects_.find(descriptor);
127 if (iterator == objects_.end()) {
128 ZLOGD(LOG_LABEL, "not found, desc:%{public}s maybe has been updated",
129 ConvertToSecureDesc(Str16ToStr8(descriptor)).c_str());
130 return false;
131 }
132
133 if (object->IsProxyObject()) {
134 proxyObjectCountNum_.fetch_sub(1, std::memory_order_relaxed);
135 }
136
137 if (iterator->second.GetRefPtr() != object) {
138 ZLOGI(LOG_LABEL, "can not erase it because addr if different, "
139 "desc:%{public}s, recorded object:%{public}u, detach object:%{public}u",
140 ConvertToSecureDesc(Str16ToStr8(descriptor)).c_str(), ConvertAddr(iterator->second.GetRefPtr()),
141 ConvertAddr(object));
142 return true;
143 }
144
145 objects_.erase(iterator);
146 ZLOGD(LOG_LABEL, "erase desc:%{public}s", ConvertToSecureDesc(Str16ToStr8(descriptor)).c_str());
147 return true;
148 }
149
AttachObject(IRemoteObject * object,const std::u16string & descriptor,bool lockFlag)150 bool ProcessSkeleton::AttachObject(IRemoteObject *object, const std::u16string &descriptor, bool lockFlag)
151 {
152 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
153 std::unique_lock<std::shared_mutex> lockGuard(objMutex_, std::defer_lock);
154 if (lockFlag) {
155 lockGuard.lock();
156 }
157 (void)isContainStub_.insert(std::pair<IRemoteObject *, bool>(object, true));
158
159 if (descriptor.empty()) {
160 ZLOGE(LOG_LABEL, "descriptor is null %{public}u", ConvertAddr(object));
161 return false;
162 }
163 // If attemptIncStrong failed, old proxy might still exist, replace it with the new proxy.
164 wptr<IRemoteObject> wp = object;
165
166 if (object->IsProxyObject()) {
167 uint64_t proxyObjectCountNum = proxyObjectCountNum_.fetch_add(1, std::memory_order_relaxed) + 1;
168 if (ipcProxyCallback_ != nullptr && ipcProxyLimitNum_ > 0 && proxyObjectCountNum > ipcProxyLimitNum_) {
169 ZLOGW(LOG_LABEL, "ipc proxy num:%{public}" PRIu64 " exceeds limit:%{public}" PRIu64,
170 proxyObjectCountNum, ipcProxyLimitNum_);
171 ipcProxyCallback_(proxyObjectCountNum);
172 }
173 }
174 auto result = objects_.insert_or_assign(descriptor, wp);
175 ZLOGD(LOG_LABEL, "attach %{public}u desc:%{public}s type:%{public}s",
176 ConvertAddr(object), ConvertToSecureDesc(Str16ToStr8(descriptor)).c_str(), result.second ? "insert" : "assign");
177 return true;
178 }
179
QueryObject(const std::u16string & descriptor,bool lockFlag)180 sptr<IRemoteObject> ProcessSkeleton::QueryObject(const std::u16string &descriptor, bool lockFlag)
181 {
182 sptr<IRemoteObject> result = nullptr;
183 if (descriptor.empty()) {
184 ZLOGE(LOG_LABEL, "descriptor is null");
185 return result;
186 }
187 IRemoteObject *remoteObject = nullptr;
188 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, nullptr);
189 {
190 std::shared_lock<std::shared_mutex> lockGuard(objMutex_, std::defer_lock);
191 ZLOGD(LOG_LABEL, "The value of lockflag is:%{public}d", lockFlag);
192 if (lockFlag) {
193 lockGuard.lock();
194 }
195 auto it = objects_.find(descriptor);
196 if (it != objects_.end()) {
197 // Life-time of IPCObjectProxy is extended to WEAK
198 // now it's weak reference counted, so it's safe to get raw pointer
199 remoteObject = it->second.GetRefPtr();
200 }
201 }
202
203 if (remoteObject == nullptr) {
204 ZLOGD(LOG_LABEL, "not found object, desc:%{public}s", ConvertToSecureDesc(Str16ToStr8(descriptor)).c_str());
205 return result;
206 }
207 std::u16string desc;
208 if (!IsValidObject(remoteObject, desc)) {
209 ZLOGD(LOG_LABEL, "object %{public}u is inValid", ConvertAddr(remoteObject));
210 return result;
211 }
212
213 if (!remoteObject->AttemptIncStrong(this)) {
214 ZLOGD(LOG_LABEL, "object %{public}u AttemptIncStrong failed", ConvertAddr(remoteObject));
215 return result;
216 }
217
218 result = remoteObject;
219 result->CheckIsAttemptAcquireSet(this);
220
221 return result;
222 }
223
LockObjectMutex()224 bool ProcessSkeleton::LockObjectMutex()
225 {
226 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
227 objMutex_.lock();
228 return true;
229 }
230
UnlockObjectMutex()231 bool ProcessSkeleton::UnlockObjectMutex()
232 {
233 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
234 objMutex_.unlock();
235 return true;
236 }
237
AttachValidObject(IRemoteObject * object,const std::u16string & desc)238 bool ProcessSkeleton::AttachValidObject(IRemoteObject *object, const std::u16string &desc)
239 {
240 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
241 std::unique_lock<std::shared_mutex> lockGuard(validObjectMutex_);
242 auto result = validObjectRecord_.insert_or_assign(object, desc);
243 ZLOGD(LOG_LABEL, "%{public}u descriptor:%{public}s", ConvertAddr(object),
244 ConvertToSecureDesc(Str16ToStr8(desc)).c_str());
245 return result.second;
246 }
247
DetachValidObject(IRemoteObject * object)248 bool ProcessSkeleton::DetachValidObject(IRemoteObject *object)
249 {
250 bool ret = false;
251 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
252 std::unique_lock<std::shared_mutex> lockGuard(validObjectMutex_);
253 auto it = validObjectRecord_.find(object);
254 if (it != validObjectRecord_.end()) {
255 ZLOGD(LOG_LABEL, "erase %{public}u ", ConvertAddr(object));
256 validObjectRecord_.erase(it);
257 ret = true;
258 }
259 return ret;
260 }
261
IsValidObject(IRemoteObject * object,std::u16string & desc)262 bool ProcessSkeleton::IsValidObject(IRemoteObject *object, std::u16string &desc)
263 {
264 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
265 if (object == nullptr) {
266 return false;
267 }
268 std::shared_lock<std::shared_mutex> lockGuard(validObjectMutex_);
269 auto it = validObjectRecord_.find(object);
270 if (it != validObjectRecord_.end()) {
271 desc = it->second;
272 ZLOGD(LOG_LABEL, "%{public}u descriptor:%{public}s", ConvertAddr(object),
273 ConvertToSecureDesc(Str16ToStr8(desc)).c_str());
274 return true;
275 }
276 return false;
277 }
278
AttachInvokerProcInfo(bool isLocal,InvokerProcInfo & invokeInfo)279 bool ProcessSkeleton::AttachInvokerProcInfo(bool isLocal, InvokerProcInfo &invokeInfo)
280 {
281 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
282 std::unique_lock<std::shared_mutex> lockGuard(invokerProcMutex_);
283 std::string key = std::to_string(gettid()) + "_" + std::to_string(isLocal);
284 auto result = invokerProcInfo_.insert_or_assign(key, invokeInfo);
285 auto &info = result.first->second;
286 ZLOGD(LOG_LABEL, "%{public}u, %{public}u %{public}u %{public}u %{public}" PRIu64 " %{public}" PRIu64,
287 info.invoker, info.pid, info.realPid, info.uid, info.tokenId, info.firstTokenId);
288 return result.second;
289 }
290
QueryInvokerProcInfo(bool isLocal,InvokerProcInfo & invokeInfo)291 bool ProcessSkeleton::QueryInvokerProcInfo(bool isLocal, InvokerProcInfo &invokeInfo)
292 {
293 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
294 std::shared_lock<std::shared_mutex> lockGuard(invokerProcMutex_);
295 std::string key = std::to_string(gettid()) + "_" + std::to_string(isLocal);
296 auto it = invokerProcInfo_.find(key);
297 if (it == invokerProcInfo_.end()) {
298 return false;
299 }
300 invokeInfo = it->second;
301 ZLOGD(LOG_LABEL, "%{public}u, %{public}u %{public}u %{public}u %{public}" PRIu64 " %{public}" PRIu64,
302 invokeInfo.invoker, invokeInfo.pid, invokeInfo.realPid, invokeInfo.uid, invokeInfo.tokenId,
303 invokeInfo.firstTokenId);
304 return true;
305 }
306
DetachInvokerProcInfo(bool isLocal)307 bool ProcessSkeleton::DetachInvokerProcInfo(bool isLocal)
308 {
309 CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
310 std::unique_lock<std::shared_mutex> lockGuard(invokerProcMutex_);
311 std::string key = std::to_string(gettid()) + "_" + std::to_string(isLocal);
312 auto it = invokerProcInfo_.find(key);
313 if (it != invokerProcInfo_.end()) {
314 auto &invokeInfo = it->second;
315 ZLOGD(LOG_LABEL, "%{public}u, %{public}u %{public}u %{public}u %{public}" PRIu64 " %{public}" PRIu64,
316 invokeInfo.invoker, invokeInfo.pid, invokeInfo.realPid, invokeInfo.uid, invokeInfo.tokenId,
317 invokeInfo.firstTokenId);
318 invokerProcInfo_.erase(it);
319 return true;
320 }
321 return false;
322 }
323
IsPrint(int err,std::atomic<int> & lastErr,std::atomic<int> & lastErrCnt)324 bool ProcessSkeleton::IsPrint(int err, std::atomic<int> &lastErr, std::atomic<int> &lastErrCnt)
325 {
326 bool isPrint = false;
327 if (err == lastErr) {
328 if (lastErrCnt >= INT_MAX) {
329 lastErrCnt = 0;
330 }
331 if (++lastErrCnt % PRINT_ERR_CNT == 0) {
332 isPrint = true;
333 }
334 } else {
335 isPrint = true;
336 lastErrCnt = 0;
337 lastErr = err;
338 }
339 return isPrint;
340 }
341
ConvertToSecureDesc(const std::string & str)342 std::string ProcessSkeleton::ConvertToSecureDesc(const std::string &str)
343 {
344 auto pos = str.find_last_of(".");
345 if (pos != std::string::npos) {
346 return "*" + str.substr(pos);
347 }
348 return str;
349 }
350
SetIPCProxyLimit(uint64_t num,std::function<void (uint64_t num)> callback)351 bool ProcessSkeleton::SetIPCProxyLimit(uint64_t num, std::function<void (uint64_t num)> callback)
352 {
353 ipcProxyLimitNum_ = num;
354 ipcProxyCallback_ = callback;
355 return true;
356 }
357
ConvertAddr(const void * ptr)358 uint32_t ProcessSkeleton::ConvertAddr(const void *ptr)
359 {
360 if (ptr == nullptr) {
361 ZLOGE(LOG_LABEL, "ptr is null");
362 return 0;
363 }
364 return static_cast<uint32_t>((reinterpret_cast<uintptr_t>(ptr)) & IPC_OBJECT_MASK);
365 }
366
FlattenDBinderData(Parcel & parcel,const dbinder_negotiation_data * & dbinderData)367 bool ProcessSkeleton::FlattenDBinderData(Parcel &parcel, const dbinder_negotiation_data *&dbinderData)
368 {
369 size_t start = parcel.GetWritePosition();
370 binder_buffer_object obj;
371 obj.hdr.type = BINDER_TYPE_PTR;
372 obj.flags = BINDER_BUFFER_FLAG_HAS_DBINDER;
373 obj.buffer = reinterpret_cast<binder_uintptr_t>(dbinderData);
374 obj.length = sizeof(dbinder_negotiation_data);
375 if (!parcel.WriteBuffer(&obj, sizeof(binder_buffer_object))) {
376 ZLOGE(LOG_LABEL, "WriteBuffer fail");
377 return false;
378 }
379 size_t stop = parcel.GetWritePosition();
380 ZLOGD(LOG_LABEL, "serialization:%{public}zu sizeof:%{public}zu", stop - start, sizeof(binder_buffer_object));
381 return true;
382 }
383
UnFlattenDBinderData(Parcel & parcel,dbinder_negotiation_data * & dbinderData)384 bool ProcessSkeleton::UnFlattenDBinderData(Parcel &parcel, dbinder_negotiation_data *&dbinderData)
385 {
386 auto *buf = parcel.ReadBuffer(sizeof(binder_buffer_object), false);
387 if (buf == nullptr) {
388 return false;
389 }
390 auto obj = reinterpret_cast<const binder_buffer_object *>(buf);
391 auto ret = memcpy_s(dbinderData, sizeof(dbinder_negotiation_data),
392 reinterpret_cast<const void *>(obj->buffer), obj->length);
393 return (ret == EOK);
394 }
395
GetSubStr(const std::string & str,std::string & substr,size_t offset,size_t length)396 bool ProcessSkeleton::GetSubStr(const std::string &str, std::string &substr, size_t offset, size_t length)
397 {
398 if (str.empty() || str.length() < offset + length) {
399 ZLOGE(LOG_LABEL, "strLen:%{public}zu, offset:%{public}zu, subLen:%{public}zu", str.length(), offset, length);
400 return false;
401 }
402 substr = str.substr(offset, length);
403 return true;
404 }
405
IsNumStr(const std::string & str)406 bool ProcessSkeleton::IsNumStr(const std::string &str)
407 {
408 if (str.empty()) {
409 return false;
410 }
411 return std::all_of(str.begin(), str.end(), ::isdigit);
412 }
413
GetThreadStopFlag()414 bool ProcessSkeleton::GetThreadStopFlag()
415 {
416 return stopThreadFlag_.load();
417 }
418
IncreaseThreadCount()419 void ProcessSkeleton::IncreaseThreadCount()
420 {
421 std::unique_lock<std::mutex> lockGuard(threadCountMutex_);
422 runningChildThreadNum_.fetch_add(1);
423 }
424
DecreaseThreadCount()425 void ProcessSkeleton::DecreaseThreadCount()
426 {
427 std::unique_lock<std::mutex> lockGuard(threadCountMutex_);
428 if (runningChildThreadNum_.load() > 0) {
429 runningChildThreadNum_.fetch_sub(1);
430
431 if (runningChildThreadNum_.load() == 0) {
432 threadCountCon_.notify_one();
433 }
434 }
435 }
436
NotifyChildThreadStop()437 void ProcessSkeleton::NotifyChildThreadStop()
438 {
439 // set child thread exit flag
440 stopThreadFlag_.store(true);
441 // after closeing fd, child threads will be not block in the 'WriteBinder' function
442 BinderConnector *connector = BinderConnector::GetInstance();
443 if (connector != nullptr) {
444 connector->CloseDriverFd();
445 }
446 ZLOGI(LOG_LABEL, "start waiting for child thread to exit, child thread num:%{public}zu",
447 runningChildThreadNum_.load());
448 std::unique_lock<std::mutex> lockGuard(threadCountMutex_);
449 threadCountCon_.wait_for(lockGuard,
450 std::chrono::seconds(MAIN_THREAD_MAX_WAIT_TIME),
451 [&threadNum = this->runningChildThreadNum_] { return threadNum.load() == 0; });
452 if (runningChildThreadNum_.load() != 0) {
453 ZLOGI(LOG_LABEL, "wait timeout, %{public}zu child threads not exiting", runningChildThreadNum_.load());
454 return;
455 }
456 ZLOGI(LOG_LABEL, "wait finished, all child thread have exited");
457 }
458 } // namespace OHOS