• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static constexpr int DEC_BASE = 10;
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     ZLOGD(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 is different, desc:%{public}s, recorded object:%{public}u,"
139             " detach object:%{public}u", ConvertToSecureDesc(Str16ToStr8(descriptor)).c_str(),
140             ConvertAddr(iterator->second.GetRefPtr()), ConvertAddr(object));
141         return true;
142     }
143 
144     objects_.erase(iterator);
145     ZLOGD(LOG_LABEL, "erase desc:%{public}s", ConvertToSecureDesc(Str16ToStr8(descriptor)).c_str());
146     return true;
147 }
148 
AttachObject(IRemoteObject * object,const std::u16string & descriptor,bool lockFlag)149 bool ProcessSkeleton::AttachObject(IRemoteObject *object, const std::u16string &descriptor, bool lockFlag)
150 {
151     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
152     std::unique_lock<std::shared_mutex> lockGuard(objMutex_, std::defer_lock);
153     if (lockFlag) {
154         lockGuard.lock();
155     }
156     (void)isContainStub_.insert(std::pair<IRemoteObject *, bool>(object, true));
157 
158     if (descriptor.empty()) {
159         ZLOGE(LOG_LABEL, "descriptor is null %{public}u", ConvertAddr(object));
160         return false;
161     }
162     // If attemptIncStrong failed, old proxy might still exist, replace it with the new proxy.
163     wptr<IRemoteObject> wp = object;
164 
165     if (object->IsProxyObject()) {
166         uint64_t proxyObjectCountNum = proxyObjectCountNum_.fetch_add(1, std::memory_order_relaxed) + 1;
167         if (ipcProxyCallback_ != nullptr && ipcProxyLimitNum_ > 0 && proxyObjectCountNum > ipcProxyLimitNum_) {
168             ZLOGW(LOG_LABEL, "ipc proxy num:%{public}" PRIu64 " exceeds limit:%{public}" PRIu64, proxyObjectCountNum,
169                 ipcProxyLimitNum_);
170             ipcProxyCallback_(proxyObjectCountNum);
171         }
172     }
173     auto result = objects_.insert_or_assign(descriptor, wp);
174     ZLOGD(LOG_LABEL, "attach %{public}u desc:%{public}s type:%{public}s", ConvertAddr(object),
175         ConvertToSecureDesc(Str16ToStr8(descriptor)).c_str(), result.second ? "insert" : "assign");
176     return true;
177 }
178 
QueryObject(const std::u16string & descriptor,bool lockFlag)179 sptr<IRemoteObject> ProcessSkeleton::QueryObject(const std::u16string &descriptor, bool lockFlag)
180 {
181     sptr<IRemoteObject> result = nullptr;
182     if (descriptor.empty()) {
183         ZLOGE(LOG_LABEL, "descriptor is null");
184         return result;
185     }
186     IRemoteObject *remoteObject = nullptr;
187     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, nullptr);
188     {
189         std::shared_lock<std::shared_mutex> lockGuard(objMutex_, std::defer_lock);
190         ZLOGD(LOG_LABEL, "The value of lockflag is:%{public}d", lockFlag);
191         if (lockFlag) {
192             lockGuard.lock();
193         }
194         auto it = objects_.find(descriptor);
195         if (it != objects_.end()) {
196             // Life-time of IPCObjectProxy is extended to WEAK
197             // now it's weak reference counted, so it's safe to get raw pointer
198             remoteObject = it->second.GetRefPtr();
199         }
200     }
201 
202     if (remoteObject == nullptr) {
203         ZLOGD(LOG_LABEL, "not found object, desc:%{public}s", ConvertToSecureDesc(Str16ToStr8(descriptor)).c_str());
204         return result;
205     }
206     std::u16string desc;
207     if (!IsValidObject(remoteObject, desc)) {
208         ZLOGD(LOG_LABEL, "object %{public}u is inValid", ConvertAddr(remoteObject));
209         return result;
210     }
211 
212     if (!remoteObject->AttemptIncStrong(this)) {
213         ZLOGD(LOG_LABEL, "object %{public}u AttemptIncStrong failed", ConvertAddr(remoteObject));
214         return result;
215     }
216 
217     result = remoteObject;
218     result->CheckIsAttemptAcquireSet(this);
219 
220     return result;
221 }
222 
LockObjectMutex()223 bool ProcessSkeleton::LockObjectMutex()
224 {
225     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
226     objMutex_.lock();
227     return true;
228 }
229 
UnlockObjectMutex()230 bool ProcessSkeleton::UnlockObjectMutex()
231 {
232     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
233     objMutex_.unlock();
234     return true;
235 }
236 
AttachValidObject(IRemoteObject * object,const std::u16string & desc)237 bool ProcessSkeleton::AttachValidObject(IRemoteObject *object, const std::u16string &desc)
238 {
239     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
240     std::unique_lock<std::shared_mutex> lockGuard(validObjectMutex_);
241     auto result = validObjectRecord_.insert_or_assign(object, desc);
242     ZLOGD(LOG_LABEL, "%{public}u descriptor:%{public}s", ConvertAddr(object),
243         ConvertToSecureDesc(Str16ToStr8(desc)).c_str());
244     return result.second;
245 }
246 
DetachValidObject(IRemoteObject * object)247 bool ProcessSkeleton::DetachValidObject(IRemoteObject *object)
248 {
249     bool ret = false;
250     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
251     std::unique_lock<std::shared_mutex> lockGuard(validObjectMutex_);
252     auto it = validObjectRecord_.find(object);
253     if (it != validObjectRecord_.end()) {
254         ZLOGD(LOG_LABEL, "erase %{public}u ", ConvertAddr(object));
255         validObjectRecord_.erase(it);
256         ret = true;
257     }
258     return ret;
259 }
260 
IsValidObject(IRemoteObject * object,std::u16string & desc)261 bool ProcessSkeleton::IsValidObject(IRemoteObject *object, std::u16string &desc)
262 {
263     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
264     if (object == nullptr) {
265         return false;
266     }
267     std::shared_lock<std::shared_mutex> lockGuard(validObjectMutex_);
268     auto it = validObjectRecord_.find(object);
269     if (it != validObjectRecord_.end()) {
270         desc = it->second;
271         return true;
272     }
273     return false;
274 }
275 
AttachInvokerProcInfo(bool isLocal,InvokerProcInfo & invokeInfo)276 bool ProcessSkeleton::AttachInvokerProcInfo(bool isLocal, InvokerProcInfo &invokeInfo)
277 {
278     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
279     std::unique_lock<std::shared_mutex> lockGuard(invokerProcMutex_);
280     std::string key = std::to_string(gettid()) + "_" + std::to_string(isLocal);
281     auto result = invokerProcInfo_.insert_or_assign(key, invokeInfo);
282     auto &info = result.first->second;
283     ZLOGD(LOG_LABEL, "%{public}u, %{public}u %{public}u %{public}u %{public}" PRIu64 " %{public}" PRIu64, info.invoker,
284         info.pid, info.realPid, info.uid, info.tokenId, info.firstTokenId);
285     return result.second;
286 }
287 
QueryInvokerProcInfo(bool isLocal,InvokerProcInfo & invokeInfo)288 bool ProcessSkeleton::QueryInvokerProcInfo(bool isLocal, InvokerProcInfo &invokeInfo)
289 {
290     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
291     std::shared_lock<std::shared_mutex> lockGuard(invokerProcMutex_);
292     std::string key = std::to_string(gettid()) + "_" + std::to_string(isLocal);
293     auto it = invokerProcInfo_.find(key);
294     if (it == invokerProcInfo_.end()) {
295         return false;
296     }
297     invokeInfo = it->second;
298     ZLOGD(LOG_LABEL, "%{public}u, %{public}u %{public}u %{public}u %{public}" PRIu64 " %{public}" PRIu64,
299         invokeInfo.invoker, invokeInfo.pid, invokeInfo.realPid, invokeInfo.uid, invokeInfo.tokenId,
300         invokeInfo.firstTokenId);
301     return true;
302 }
303 
DetachInvokerProcInfo(bool isLocal)304 bool ProcessSkeleton::DetachInvokerProcInfo(bool isLocal)
305 {
306     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
307     std::unique_lock<std::shared_mutex> lockGuard(invokerProcMutex_);
308     std::string key = std::to_string(gettid()) + "_" + std::to_string(isLocal);
309     auto it = invokerProcInfo_.find(key);
310     if (it != invokerProcInfo_.end()) {
311         auto &invokeInfo = it->second;
312         ZLOGD(LOG_LABEL, "%{public}u, %{public}u %{public}u %{public}u %{public}" PRIu64 " %{public}" PRIu64,
313             invokeInfo.invoker, invokeInfo.pid, invokeInfo.realPid, invokeInfo.uid, invokeInfo.tokenId,
314             invokeInfo.firstTokenId);
315         invokerProcInfo_.erase(it);
316         return true;
317     }
318     return false;
319 }
320 
IsPrint(int err,std::atomic<int> & lastErr,std::atomic<int> & lastErrCnt)321 bool ProcessSkeleton::IsPrint(int err, std::atomic<int> &lastErr, std::atomic<int> &lastErrCnt)
322 {
323     bool isPrint = false;
324     if (err == lastErr) {
325         if (lastErrCnt >= INT_MAX) {
326             lastErrCnt = 0;
327         }
328         if (++lastErrCnt % PRINT_ERR_CNT == 0) {
329             isPrint = true;
330         }
331     } else {
332         isPrint = true;
333         lastErrCnt = 0;
334         lastErr = err;
335     }
336     return isPrint;
337 }
338 
ConvertToSecureDesc(const std::string & str)339 std::string ProcessSkeleton::ConvertToSecureDesc(const std::string &str)
340 {
341     auto pos = str.find_last_of(".");
342     if (pos != std::string::npos) {
343         return "*" + str.substr(pos);
344     }
345     return str;
346 }
347 
SetIPCProxyLimit(uint64_t num,std::function<void (uint64_t num)> callback)348 bool ProcessSkeleton::SetIPCProxyLimit(uint64_t num, std::function<void(uint64_t num)> callback)
349 {
350     ipcProxyLimitNum_ = num;
351     ipcProxyCallback_ = callback;
352     return true;
353 }
354 
ConvertAddr(const void * ptr)355 uint32_t ProcessSkeleton::ConvertAddr(const void *ptr)
356 {
357     if (ptr == nullptr) {
358         ZLOGE(LOG_LABEL, "ptr is null");
359         return 0;
360     }
361     return static_cast<uint32_t>((reinterpret_cast<uintptr_t>(ptr)) & IPC_OBJECT_MASK);
362 }
363 
FlattenDBinderData(Parcel & parcel,const dbinder_negotiation_data * & dbinderData)364 bool ProcessSkeleton::FlattenDBinderData(Parcel &parcel, const dbinder_negotiation_data *&dbinderData)
365 {
366     size_t start = parcel.GetWritePosition();
367     binder_buffer_object obj;
368     obj.hdr.type = BINDER_TYPE_PTR;
369     obj.flags = BINDER_BUFFER_FLAG_HAS_DBINDER;
370     obj.buffer = reinterpret_cast<binder_uintptr_t>(dbinderData);
371     obj.length = sizeof(dbinder_negotiation_data);
372     if (!parcel.WriteBuffer(&obj, sizeof(binder_buffer_object))) {
373         ZLOGE(LOG_LABEL, "WriteBuffer fail");
374         return false;
375     }
376     size_t stop = parcel.GetWritePosition();
377     ZLOGD(LOG_LABEL, "serialization:%{public}zu sizeof:%{public}zu", stop - start, sizeof(binder_buffer_object));
378     return true;
379 }
380 
UnFlattenDBinderData(Parcel & parcel,dbinder_negotiation_data * & dbinderData)381 bool ProcessSkeleton::UnFlattenDBinderData(Parcel &parcel, dbinder_negotiation_data *&dbinderData)
382 {
383     auto *buf = parcel.ReadBuffer(sizeof(binder_buffer_object), false);
384     if (buf == nullptr) {
385         return false;
386     }
387     auto obj = reinterpret_cast<const binder_buffer_object *>(buf);
388     auto ret = memcpy_s(dbinderData, sizeof(dbinder_negotiation_data), reinterpret_cast<const void *>(obj->buffer),
389         obj->length);
390     return (ret == EOK);
391 }
392 
GetSubStr(const std::string & str,std::string & substr,size_t offset,size_t length)393 bool ProcessSkeleton::GetSubStr(const std::string &str, std::string &substr, size_t offset, size_t length)
394 {
395     if (str.empty() || str.length() < offset + length) {
396         ZLOGE(LOG_LABEL, "strLen:%{public}zu, offset:%{public}zu, subLen:%{public}zu", str.length(), offset, length);
397         return false;
398     }
399     substr = str.substr(offset, length);
400     return true;
401 }
402 
IsNumStr(const std::string & str)403 bool ProcessSkeleton::IsNumStr(const std::string &str)
404 {
405     if (str.empty()) {
406         return false;
407     }
408     return std::all_of(str.begin(), str.end(), ::isdigit);
409 }
410 
411 template <typename V, typename F>
StrToInteger(const std::string & str,V & value,F func)412 static bool StrToInteger(const std::string &str, V &value, F func)
413 {
414     if (str.empty()) {
415         ZLOGE(LOG_LABEL, "empty input");
416         return false;
417     }
418 
419     const char *begin = str.c_str();
420     char *end = nullptr;
421     errno = 0;
422     V valueTmp = func(begin, &end, DEC_BASE);
423     if (errno == ERANGE) {
424         ZLOGE(LOG_LABEL, "out of range");
425         return false;
426     }
427 
428     if (end == begin || end[0] != '\0') {
429         ZLOGE(LOG_LABEL, "illegal input");
430         return false;
431     }
432     value = valueTmp;
433     return true;
434 }
435 
StrToUint64(const std::string & str,uint64_t & value)436 bool ProcessSkeleton::StrToUint64(const std::string &str, uint64_t &value)
437 {
438     uint64_t valueTmp = 0;
439     if (!StrToInteger(str, valueTmp, strtoull)) {
440         return false;
441     }
442     value = valueTmp;
443     return true;
444 }
445 
StrToInt32(const std::string & str,int32_t & value)446 bool ProcessSkeleton::StrToInt32(const std::string &str, int32_t &value)
447 {
448     int64_t valueTmp = 0;
449     if (!StrToInteger(str, valueTmp, strtoll)) {
450         return false;
451     }
452     if ((valueTmp < INT32_MIN || valueTmp > INT32_MAX)) {
453         ZLOGE(LOG_LABEL, "out of range, str:%{public}s", str.c_str());
454         return false;
455     }
456     value = static_cast<int32_t>(valueTmp);
457     return true;
458 }
459 
GetThreadStopFlag()460 bool ProcessSkeleton::GetThreadStopFlag()
461 {
462     return stopThreadFlag_.load();
463 }
464 
IncreaseThreadCount()465 void ProcessSkeleton::IncreaseThreadCount()
466 {
467     std::unique_lock<std::mutex> lockGuard(threadCountMutex_);
468     runningChildThreadNum_.fetch_add(1);
469 }
470 
DecreaseThreadCount()471 void ProcessSkeleton::DecreaseThreadCount()
472 {
473     std::unique_lock<std::mutex> lockGuard(threadCountMutex_);
474     if (runningChildThreadNum_.load() > 0) {
475         runningChildThreadNum_.fetch_sub(1);
476 
477         if (runningChildThreadNum_.load() == 0) {
478             threadCountCon_.notify_one();
479         }
480     }
481 }
482 
NotifyChildThreadStop()483 void ProcessSkeleton::NotifyChildThreadStop()
484 {
485     // set child thread exit flag
486     stopThreadFlag_.store(true);
487     // after closeing fd, child threads will be not block in the 'WriteBinder' function
488     BinderConnector *connector = BinderConnector::GetInstance();
489     if (connector != nullptr) {
490         connector->CloseDriverFd();
491     }
492     ZLOGI(LOG_LABEL, "start waiting for child thread to exit, child thread num:%{public}zu",
493         runningChildThreadNum_.load());
494     std::unique_lock<std::mutex> lockGuard(threadCountMutex_);
495     threadCountCon_.wait_for(lockGuard, std::chrono::seconds(MAIN_THREAD_MAX_WAIT_TIME),
496         [&threadNum = this->runningChildThreadNum_] {
497             return threadNum.load() == 0;
498         });
499     if (runningChildThreadNum_.load() != 0) {
500         ZLOGI(LOG_LABEL, "wait timeout, %{public}zu child threads not exiting", runningChildThreadNum_.load());
501         return;
502     }
503     ZLOGI(LOG_LABEL, "wait finished, all child thread have exited");
504 }
505 } // namespace OHOS