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