• 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 
43 // LCOV_EXCL_START
GetInstance()44 ProcessSkeleton* ProcessSkeleton::GetInstance()
45 {
46     if ((instance_ == nullptr) && !exitFlag_) {
47         std::lock_guard<std::mutex> lockGuard(mutex_);
48         if ((instance_ == nullptr) && !exitFlag_) {
49             instance_ = new (std::nothrow) ProcessSkeleton();
50             if (instance_ == nullptr) {
51                 ZLOGE(LOG_LABEL, "create ProcessSkeleton object failed");
52                 return nullptr;
53             }
54         }
55     }
56     return instance_;
57 }
58 // LCOV_EXCL_STOP
59 
~ProcessSkeleton()60 ProcessSkeleton::~ProcessSkeleton()
61 {
62     ZLOGD(LOG_LABEL, "enter");
63     std::lock_guard<std::mutex> lockGuard(mutex_);
64     exitFlag_ = true;
65     {
66         std::unique_lock<std::shared_mutex> objLock(objMutex_);
67         objects_.clear();
68         isContainStub_.clear();
69     }
70     {
71         std::unique_lock<std::shared_mutex> validObjLock(validObjectMutex_);
72         validObjectRecord_.clear();
73     }
74     {
75         std::unique_lock<std::shared_mutex> invokerProcLock(invokerProcMutex_);
76         invokerProcInfo_.clear();
77     }
78 }
79 
GetRegistryObject()80 sptr<IRemoteObject> ProcessSkeleton::GetRegistryObject()
81 {
82     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, nullptr);
83     std::lock_guard<std::mutex> lockGuard(mutex_);
84     return registryObject_;
85 }
86 
SetRegistryObject(sptr<IRemoteObject> & object)87 void ProcessSkeleton::SetRegistryObject(sptr<IRemoteObject> &object)
88 {
89     CHECK_INSTANCE_EXIT(exitFlag_);
90     std::lock_guard<std::mutex> lockGuard(mutex_);
91     registryObject_ = object;
92 }
93 
SetSamgrFlag(bool flag)94 void ProcessSkeleton::SetSamgrFlag(bool flag)
95 {
96     isSamgr_ = flag;
97 }
98 
GetSamgrFlag()99 bool ProcessSkeleton::GetSamgrFlag()
100 {
101     return isSamgr_;
102 }
103 
IsContainsObject(IRemoteObject * object)104 bool ProcessSkeleton::IsContainsObject(IRemoteObject *object)
105 {
106     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
107     if (object == nullptr) {
108         return false;
109     }
110     // check whether it is a valid IPCObjectStub object.
111     std::shared_lock<std::shared_mutex> lockGuard(objMutex_);
112     auto it = isContainStub_.find(object);
113     if (it != isContainStub_.end()) {
114         return it->second;
115     }
116 
117     return false;
118 }
119 
DetachObject(IRemoteObject * object,const std::u16string & descriptor)120 bool ProcessSkeleton::DetachObject(IRemoteObject *object, const std::u16string &descriptor)
121 {
122     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
123     std::unique_lock<std::shared_mutex> lockGuard(objMutex_);
124     (void)isContainStub_.erase(object);
125 
126     // This handle may have already been replaced with a new IPCObjectProxy,
127     // if someone failed the AttemptIncStrong.
128     auto iterator = objects_.find(descriptor);
129     if (iterator == objects_.end()) {
130         ZLOGD(LOG_LABEL, "not found, desc:%{public}s maybe has been updated",
131             ConvertToSecureDesc(Str16ToStr8(descriptor)).c_str());
132         return false;
133     }
134 
135     if (object->IsProxyObject()) {
136         proxyObjectCountNum_.fetch_sub(1, std::memory_order_relaxed);
137         if (iterator->second.GetRefPtr() != object) {
138             ZLOGD(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 
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, proxyObjectCountNum,
170                 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", ConvertAddr(object),
176         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         return true;
273     }
274     return false;
275 }
276 
AttachInvokerProcInfo(bool isLocal,InvokerProcInfo & invokeInfo)277 bool ProcessSkeleton::AttachInvokerProcInfo(bool isLocal, InvokerProcInfo &invokeInfo)
278 {
279     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
280     std::unique_lock<std::shared_mutex> lockGuard(invokerProcMutex_);
281     std::string key = std::to_string(gettid()) + "_" + std::to_string(isLocal);
282     auto result = invokerProcInfo_.insert_or_assign(key, invokeInfo);
283     auto &info = result.first->second;
284     ZLOGD(LOG_LABEL, "%{public}u, %{public}u %{public}u %{public}u %{public}" PRIu64 " %{public}" PRIu64, info.invoker,
285         info.pid, info.realPid, info.uid, info.tokenId, info.firstTokenId);
286     return result.second;
287 }
288 
QueryInvokerProcInfo(bool isLocal,InvokerProcInfo & invokeInfo)289 bool ProcessSkeleton::QueryInvokerProcInfo(bool isLocal, InvokerProcInfo &invokeInfo)
290 {
291     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
292     std::shared_lock<std::shared_mutex> lockGuard(invokerProcMutex_);
293     std::string key = std::to_string(gettid()) + "_" + std::to_string(isLocal);
294     auto it = invokerProcInfo_.find(key);
295     if (it == invokerProcInfo_.end()) {
296         return false;
297     }
298     invokeInfo = it->second;
299     ZLOGD(LOG_LABEL, "%{public}u, %{public}u %{public}u %{public}u %{public}" PRIu64 " %{public}" PRIu64,
300         invokeInfo.invoker, invokeInfo.pid, invokeInfo.realPid, invokeInfo.uid, invokeInfo.tokenId,
301         invokeInfo.firstTokenId);
302     return true;
303 }
304 
DetachInvokerProcInfo(bool isLocal)305 bool ProcessSkeleton::DetachInvokerProcInfo(bool isLocal)
306 {
307     CHECK_INSTANCE_EXIT_WITH_RETVAL(exitFlag_, false);
308     std::unique_lock<std::shared_mutex> lockGuard(invokerProcMutex_);
309     std::string key = std::to_string(gettid()) + "_" + std::to_string(isLocal);
310     auto it = invokerProcInfo_.find(key);
311     if (it != invokerProcInfo_.end()) {
312         auto &invokeInfo = it->second;
313         ZLOGD(LOG_LABEL, "%{public}u, %{public}u %{public}u %{public}u %{public}" PRIu64 " %{public}" PRIu64,
314             invokeInfo.invoker, invokeInfo.pid, invokeInfo.realPid, invokeInfo.uid, invokeInfo.tokenId,
315             invokeInfo.firstTokenId);
316         invokerProcInfo_.erase(it);
317         return true;
318     }
319     return false;
320 }
321 
IsPrint(int err,std::atomic<int> & lastErr,std::atomic<int> & lastErrCnt)322 bool ProcessSkeleton::IsPrint(int err, std::atomic<int> &lastErr, std::atomic<int> &lastErrCnt)
323 {
324     bool isPrint = false;
325     if (err == lastErr) {
326         if (lastErrCnt >= INT_MAX) {
327             lastErrCnt = 0;
328         }
329         if (++lastErrCnt % PRINT_ERR_CNT == 0) {
330             isPrint = true;
331         }
332     } else {
333         isPrint = true;
334         lastErrCnt = 0;
335         lastErr = err;
336     }
337     return isPrint;
338 }
339 
ConvertToSecureDesc(const std::string & str)340 std::string ProcessSkeleton::ConvertToSecureDesc(const std::string &str)
341 {
342     auto pos = str.find_last_of(".");
343     if (pos != std::string::npos) {
344         return "*" + str.substr(pos);
345     }
346     return str;
347 }
348 
SetIPCProxyLimit(uint64_t num,std::function<void (uint64_t num)> callback)349 bool ProcessSkeleton::SetIPCProxyLimit(uint64_t num, std::function<void(uint64_t num)> callback)
350 {
351     ipcProxyLimitNum_ = num;
352     ipcProxyCallback_ = callback;
353     return true;
354 }
355 
ConvertAddr(const void * ptr)356 uint32_t ProcessSkeleton::ConvertAddr(const void *ptr)
357 {
358     if (ptr == nullptr) {
359         ZLOGE(LOG_LABEL, "ptr is null");
360         return 0;
361     }
362     return static_cast<uint32_t>((reinterpret_cast<uintptr_t>(ptr)) & IPC_OBJECT_MASK);
363 }
364 
FlattenDBinderData(Parcel & parcel,const dbinder_negotiation_data * & dbinderData)365 bool ProcessSkeleton::FlattenDBinderData(Parcel &parcel, const dbinder_negotiation_data *&dbinderData)
366 {
367     size_t start = parcel.GetWritePosition();
368     binder_buffer_object obj;
369     obj.hdr.type = BINDER_TYPE_PTR;
370     obj.flags = BINDER_BUFFER_FLAG_HAS_DBINDER;
371     obj.buffer = reinterpret_cast<binder_uintptr_t>(dbinderData);
372     obj.length = sizeof(dbinder_negotiation_data);
373     if (!parcel.WriteBuffer(&obj, sizeof(binder_buffer_object))) {
374         ZLOGE(LOG_LABEL, "WriteBuffer fail");
375         return false;
376     }
377     size_t stop = parcel.GetWritePosition();
378     ZLOGD(LOG_LABEL, "serialization:%{public}zu sizeof:%{public}zu", stop - start, sizeof(binder_buffer_object));
379     return true;
380 }
381 
UnFlattenDBinderData(Parcel & parcel,dbinder_negotiation_data * & dbinderData)382 bool ProcessSkeleton::UnFlattenDBinderData(Parcel &parcel, dbinder_negotiation_data *&dbinderData)
383 {
384     auto *buf = parcel.ReadBuffer(sizeof(binder_buffer_object), false);
385     if (buf == nullptr) {
386         return false;
387     }
388     auto obj = reinterpret_cast<const binder_buffer_object *>(buf);
389     auto ret = memcpy_s(dbinderData, sizeof(dbinder_negotiation_data), reinterpret_cast<const void *>(obj->buffer),
390         obj->length);
391     return (ret == EOK);
392 }
393 
GetSubStr(const std::string & str,std::string & substr,size_t offset,size_t length)394 bool ProcessSkeleton::GetSubStr(const std::string &str, std::string &substr, size_t offset, size_t length)
395 {
396     if (str.empty() || str.length() < offset + length) {
397         ZLOGE(LOG_LABEL, "strLen:%{public}zu, offset:%{public}zu, subLen:%{public}zu", str.length(), offset, length);
398         return false;
399     }
400     substr = str.substr(offset, length);
401     return true;
402 }
403 
IsNumStr(const std::string & str)404 bool ProcessSkeleton::IsNumStr(const std::string &str)
405 {
406     if (str.empty()) {
407         return false;
408     }
409     return std::all_of(str.begin(), str.end(), ::isdigit);
410 }
411 
412 template <typename V, typename F>
StrToInteger(const std::string & str,V & value,F func)413 static bool StrToInteger(const std::string &str, V &value, F func)
414 {
415     if (str.empty()) {
416         ZLOGE(LOG_LABEL, "empty input");
417         return false;
418     }
419 
420     const char *begin = str.c_str();
421     char *end = nullptr;
422     errno = 0;
423     V valueTmp = func(begin, &end, DEC_BASE);
424     if (errno == ERANGE) {
425         ZLOGE(LOG_LABEL, "out of range");
426         return false;
427     }
428 
429     if (end == begin || end[0] != '\0') {
430         ZLOGE(LOG_LABEL, "illegal input");
431         return false;
432     }
433     value = valueTmp;
434     return true;
435 }
436 
StrToUint64(const std::string & str,uint64_t & value)437 bool ProcessSkeleton::StrToUint64(const std::string &str, uint64_t &value)
438 {
439     uint64_t valueTmp = 0;
440     if (!StrToInteger(str, valueTmp, strtoull)) {
441         return false;
442     }
443     value = valueTmp;
444     return true;
445 }
446 
StrToInt32(const std::string & str,int32_t & value)447 bool ProcessSkeleton::StrToInt32(const std::string &str, int32_t &value)
448 {
449     int64_t valueTmp = 0;
450     if (!StrToInteger(str, valueTmp, strtoll)) {
451         return false;
452     }
453     if ((valueTmp < INT32_MIN || valueTmp > INT32_MAX)) {
454         ZLOGE(LOG_LABEL, "out of range, str:%{public}s", str.c_str());
455         return false;
456     }
457     value = static_cast<int32_t>(valueTmp);
458     return true;
459 }
460 
GetThreadStopFlag()461 bool ProcessSkeleton::GetThreadStopFlag()
462 {
463     return stopThreadFlag_.load();
464 }
465 
IncreaseThreadCount()466 void ProcessSkeleton::IncreaseThreadCount()
467 {
468     std::unique_lock<std::mutex> lockGuard(threadCountMutex_);
469     runningChildThreadNum_.fetch_add(1);
470 }
471 
DecreaseThreadCount()472 void ProcessSkeleton::DecreaseThreadCount()
473 {
474     std::unique_lock<std::mutex> lockGuard(threadCountMutex_);
475     if (runningChildThreadNum_.load() > 0) {
476         runningChildThreadNum_.fetch_sub(1);
477 
478         if (runningChildThreadNum_.load() == 0) {
479             threadCountCon_.notify_one();
480         }
481     }
482 }
483 
NotifyChildThreadStop()484 void ProcessSkeleton::NotifyChildThreadStop()
485 {
486     // set child thread exit flag
487     stopThreadFlag_.store(true);
488     // after closeing fd, child threads will be not block in the 'WriteBinder' function
489     BinderConnector *connector = BinderConnector::GetInstance();
490     if (connector != nullptr) {
491         connector->CloseDriverFd();
492     }
493     ZLOGD(LOG_LABEL, "start waiting for child thread to exit, child thread num:%{public}zu",
494         runningChildThreadNum_.load());
495     std::unique_lock<std::mutex> lockGuard(threadCountMutex_);
496     threadCountCon_.wait_for(lockGuard, std::chrono::seconds(MAIN_THREAD_MAX_WAIT_TIME),
497         [&threadNum = this->runningChildThreadNum_] {
498             return threadNum.load() == 0;
499         });
500     if (runningChildThreadNum_.load() != 0) {
501         ZLOGI(LOG_LABEL, "wait timeout, %{public}zu child threads not exiting", runningChildThreadNum_.load());
502         return;
503     }
504     ZLOGD(LOG_LABEL, "wait finished, all child thread have exited");
505 }
506 } // namespace OHOS