1 /*
2  * Copyright (c) 2023 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 "open_dlp_file_callback_manager.h"
17 
18 #include <datetime_ex.h>
19 #include <future>
20 #include <pthread.h>
21 #include <thread>
22 
23 #include "dlp_permission.h"
24 #include "dlp_permission_log.h"
25 #include "open_dlp_file_callback_info.h"
26 #include "open_dlp_file_callback_death_recipient.h"
27 #include "i_open_dlp_file_callback.h"
28 
29 namespace OHOS {
30 namespace Security {
31 namespace DlpPermission {
32 namespace {
33 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {
34     LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION, "OpenDlpFileCallbackManager"};
35 static const uint32_t MAX_CALLBACK_SIZE = 100;
36 static const uint32_t MAX_CALLBACKS = 100;
37 const char THREAD_EVENT[] = "openDlpFile";
38 }  // namespace
39 
GetInstance()40 OpenDlpFileCallbackManager& OpenDlpFileCallbackManager::GetInstance()
41 {
42     static OpenDlpFileCallbackManager instance;
43     return instance;
44 }
45 
OpenDlpFileCallbackManager()46 OpenDlpFileCallbackManager::OpenDlpFileCallbackManager()
47     : callbackDeathRecipient_(
48           sptr<IRemoteObject::DeathRecipient>(new(std::nothrow) OpenDlpFileCallbackDeathRecipient()))
49 {}
50 
~OpenDlpFileCallbackManager()51 OpenDlpFileCallbackManager::~OpenDlpFileCallbackManager()
52 {}
53 
AddCallback(int32_t pid,int32_t userId,const std::string & bundleName,const sptr<IRemoteObject> & callback)54 int32_t OpenDlpFileCallbackManager::AddCallback(
55     int32_t pid, int32_t userId, const std::string& bundleName, const sptr<IRemoteObject>& callback)
56 {
57     if (callback == nullptr) {
58         DLP_LOG_ERROR(LABEL, "input is nullptr");
59         return DLP_SERVICE_ERROR_VALUE_INVALID;
60     }
61 
62     std::lock_guard<std::mutex> lock(mutex_);
63     if (openDlpFileCallbackMap_.size() >= MAX_CALLBACK_SIZE) {
64         DLP_LOG_ERROR(LABEL, "callback size has reached limitation");
65         return DLP_SERVICE_ERROR_VALUE_INVALID;
66     }
67     callback->AddDeathRecipient(callbackDeathRecipient_);
68     auto goalCallback = openDlpFileCallbackMap_.find(pid);
69     if (goalCallback != openDlpFileCallbackMap_.end()) {
70         DLP_LOG_INFO(LABEL, "callbacks in %{public}d not empty", pid);
71         auto &callbackList = goalCallback->second;
72         if (callbackList.size() >= MAX_CALLBACKS) {
73             DLP_LOG_ERROR(LABEL, "callbacks in %{public}d has reached limitation", pid);
74             return DLP_SERVICE_ERROR_VALUE_INVALID;
75         }
76         bool findCallBack = std::any_of(callbackList.begin(), callbackList.end(),
77             [callback](const auto& callbackRecord) { return callbackRecord.callbackObject == callback; });
78         if (findCallBack) {
79             DLP_LOG_ERROR(LABEL, "same callback already in %{public}d", pid);
80             return DLP_OK;
81         }
82     }
83     OpenDlpFileCallbackRecord recordInstance;
84     recordInstance.callbackObject = callback;
85     recordInstance.userId = userId;
86     recordInstance.bundleName = bundleName;
87     openDlpFileCallbackMap_[pid].emplace_back(recordInstance);
88     DLP_LOG_INFO(LABEL, "callback add in %{public}d", pid);
89     return DLP_OK;
90 }
91 
RemoveCallback(const sptr<IRemoteObject> & callback)92 int32_t OpenDlpFileCallbackManager::RemoveCallback(const sptr<IRemoteObject>& callback)
93 {
94     DLP_LOG_INFO(LABEL, "RemoveCallback by kill");
95     if (callback == nullptr) {
96         DLP_LOG_ERROR(LABEL, "callback is nullptr");
97         return DLP_SERVICE_ERROR_VALUE_INVALID;
98     }
99 
100     std::lock_guard<std::mutex> lock(mutex_);
101     for (auto it = openDlpFileCallbackMap_.begin(); it != openDlpFileCallbackMap_.end(); ++it) {
102         auto &callbackList = it->second;
103         auto callbackIter = callbackList.begin();
104         while (callbackIter != callbackList.end()) {
105             if (callbackIter->callbackObject != callback) {
106                 callbackIter++;
107                 continue;
108             }
109             DLP_LOG_INFO(LABEL, "find callback in %{public}d", it->first);
110             if (callbackDeathRecipient_ != nullptr) {
111                 callback->RemoveDeathRecipient(callbackDeathRecipient_);
112             }
113             callbackList.erase(callbackIter);
114             if (callbackList.empty()) {
115                 DLP_LOG_INFO(LABEL, "Remove empty callback list in %{public}d", it->first);
116                 openDlpFileCallbackMap_.erase(it);
117             }
118             return DLP_OK;
119         }
120     }
121     DLP_LOG_INFO(LABEL, "Remove callback not found");
122     return DLP_OK;
123 }
124 
RemoveCallback(int32_t pid,const sptr<IRemoteObject> & callback)125 int32_t OpenDlpFileCallbackManager::RemoveCallback(int32_t pid, const sptr<IRemoteObject>& callback)
126 {
127     DLP_LOG_INFO(LABEL, "RemoveCallback");
128     if (pid == 0) {
129         DLP_LOG_ERROR(LABEL, "pid == 0");
130         return DLP_SERVICE_ERROR_VALUE_INVALID;
131     }
132 
133     std::lock_guard<std::mutex> lock(mutex_);
134     auto goalCallback = openDlpFileCallbackMap_.find(pid);
135     if (goalCallback == openDlpFileCallbackMap_.end()) {
136         DLP_LOG_ERROR(LABEL, "can not find %{public}d's callback", pid);
137         return DLP_CALLBACK_PARAM_INVALID;
138     }
139     auto &callbackList = goalCallback->second;
140     auto callbackIter = callbackList.begin();
141     while (callbackIter != callbackList.end()) {
142         if (callbackIter->callbackObject != callback) {
143             callbackIter++;
144             continue;
145         }
146         DLP_LOG_INFO(LABEL, "find callback in %{public}d", pid);
147         if ((callbackDeathRecipient_ != nullptr) && (callback != nullptr)) {
148             callback->RemoveDeathRecipient(callbackDeathRecipient_);
149         }
150         callbackList.erase(callbackIter);
151         if (callbackList.empty()) {
152             DLP_LOG_INFO(LABEL, "Remove empty callback list in %{public}d", pid);
153             openDlpFileCallbackMap_.erase(goalCallback);
154         }
155         return DLP_OK;
156     }
157     DLP_LOG_INFO(LABEL, "Remove callback not found");
158     return DLP_OK;
159 }
160 
OnOpenDlpFile(const sptr<IRemoteObject> & subscribeRecordPtr,const DlpSandboxInfo & dlpSandboxInfo)161 bool OpenDlpFileCallbackManager::OnOpenDlpFile(
162     const sptr<IRemoteObject>& subscribeRecordPtr, const DlpSandboxInfo& dlpSandboxInfo)
163 {
164     auto callback = iface_cast<IOpenDlpFileCallback>(subscribeRecordPtr);
165     if (callback != nullptr) {
166         DLP_LOG_INFO(LABEL, "callback excute");
167         OpenDlpFileCallbackInfo resInfo;
168         resInfo.uri = dlpSandboxInfo.uri;
169         resInfo.timeStamp = dlpSandboxInfo.timeStamp;
170         callback->OnOpenDlpFile(resInfo);
171     }
172     return false;
173 }
174 
ExecuteCallbackAsync(const DlpSandboxInfo & dlpSandboxInfo)175 void OpenDlpFileCallbackManager::ExecuteCallbackAsync(const DlpSandboxInfo& dlpSandboxInfo)
176 {
177     std::vector<sptr<IRemoteObject>> callbackList;
178     {
179         std::lock_guard<std::mutex> lock(mutex_);
180         for (const auto& iter : openDlpFileCallbackMap_) {
181             auto list = iter.second;
182             for (auto& it : list) {
183                 if ((it.bundleName == dlpSandboxInfo.bundleName) && (it.userId == dlpSandboxInfo.userId)) {
184                     callbackList.emplace_back(it.callbackObject);
185                 }
186             }
187         }
188     }
189     if (callbackList.empty()) {
190         DLP_LOG_INFO(LABEL, "no callback to execution");
191         return;
192     }
193     uint32_t sendCnt = 0;
194     for (const auto& iter : callbackList) {
195         auto task = [this, iter, dlpSandboxInfo] { this->OnOpenDlpFile(iter, dlpSandboxInfo); };
196         std::thread taskThread(task);
197         pthread_setname_np(taskThread.native_handle(), THREAD_EVENT);
198         taskThread.detach();
199         ++sendCnt;
200     }
201     DLP_LOG_INFO(LABEL, "callback execution is complete, total %{public}d", sendCnt);
202 }
203 
IsCallbackEmpty()204 bool OpenDlpFileCallbackManager::IsCallbackEmpty()
205 {
206     std::lock_guard<std::mutex> lock(mutex_);
207     size_t num = openDlpFileCallbackMap_.size();
208     DLP_LOG_INFO(LABEL, "current callback %{public}zu", num);
209     return num == 0;
210 }
211 }  // namespace DlpPermission
212 }  // namespace Security
213 }  // namespace OHOS
214