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 "dlp_sandbox_change_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 "dlp_sandbox_callback_info.h"
26 #include "dlp_sandbox_change_callback_death_recipient.h"
27 #include "i_dlp_sandbox_state_change_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, "DlpSandboxChangeCallbackManager"};
35 static const time_t MAX_TIMEOUT_SEC = 30;
36 static const uint32_t MAX_CALLBACK_SIZE = 1024;
37 static const int MAX_PTHREAD_NAME_LEN = 15; // pthread name max length
38 }
39 
GetInstance()40 DlpSandboxChangeCallbackManager &DlpSandboxChangeCallbackManager::GetInstance()
41 {
42     static DlpSandboxChangeCallbackManager instance;
43     return instance;
44 }
45 
DlpSandboxChangeCallbackManager()46 DlpSandboxChangeCallbackManager::DlpSandboxChangeCallbackManager()
47     : callbackDeathRecipient_(
48     sptr<IRemoteObject::DeathRecipient>(new (std::nothrow) DlpSandboxChangeCallbackDeathRecipient()))
49 {}
50 
~DlpSandboxChangeCallbackManager()51 DlpSandboxChangeCallbackManager::~DlpSandboxChangeCallbackManager() {}
52 
AddCallback(int32_t pid,const sptr<IRemoteObject> & callback)53 int32_t DlpSandboxChangeCallbackManager::AddCallback(int32_t pid, const sptr<IRemoteObject> &callback)
54 {
55     if (callback == nullptr) {
56         DLP_LOG_ERROR(LABEL, "input is nullptr");
57         return DLP_SERVICE_ERROR_VALUE_INVALID;
58     }
59 
60     std::lock_guard<std::mutex> lock(mutex_);
61     if (callbackInfoMap_.size() >= MAX_CALLBACK_SIZE) {
62         DLP_LOG_ERROR(LABEL, "callback size has reached limitation");
63         return DLP_SERVICE_ERROR_VALUE_INVALID;
64     }
65     callback->AddDeathRecipient(callbackDeathRecipient_);
66     auto goalCallback = callbackInfoMap_.find(pid);
67     if (goalCallback != callbackInfoMap_.end()) {
68         DLP_LOG_ERROR(LABEL, "already has the same callback");
69         return DLP_SERVICE_ERROR_VALUE_INVALID;
70     }
71     DlpSandboxChangeCallbackRecord recordInstance;
72     recordInstance.callbackObject_ = callback;
73     recordInstance.pid = pid;
74     callbackInfoMap_[pid] = recordInstance;
75     DLP_LOG_INFO(LABEL, "recordInstance is added");
76     return DLP_OK;
77 }
78 
RemoveCallback(const sptr<IRemoteObject> & callback)79 int32_t DlpSandboxChangeCallbackManager::RemoveCallback(const sptr<IRemoteObject> &callback)
80 {
81     DLP_LOG_INFO(LABEL, "enter RemoveCallback by kill");
82     if (callback == nullptr) {
83         DLP_LOG_ERROR(LABEL, "callback is nullptr");
84         return DLP_SERVICE_ERROR_VALUE_INVALID;
85     }
86 
87     std::lock_guard<std::mutex> lock(mutex_);
88     for (auto it = callbackInfoMap_.begin(); it != callbackInfoMap_.end(); ++it) {
89         if (callback == it->second.callbackObject_) {
90             DLP_LOG_INFO(LABEL, "find callback");
91             if (callbackDeathRecipient_ != nullptr) {
92                 callback->RemoveDeathRecipient(callbackDeathRecipient_);
93             }
94             it->second.callbackObject_ = nullptr;
95             callbackInfoMap_.erase(it);
96             DLP_LOG_INFO(LABEL, "callbackInfo RemoveCallback from DeathRecipient succuss");
97             return DLP_OK;
98         }
99     }
100     DLP_LOG_INFO(LABEL, "RemoveCallback from DeathRecipient can not find callbackInfo");
101     return DLP_OK;
102 }
103 
RemoveCallback(int32_t pid,bool & result)104 int32_t DlpSandboxChangeCallbackManager::RemoveCallback(int32_t pid, bool &result)
105 {
106     DLP_LOG_INFO(LABEL, "enter RemoveCallback");
107     if (pid == 0) {
108         DLP_LOG_ERROR(LABEL, "pid == 0");
109         return DLP_SERVICE_ERROR_VALUE_INVALID;
110     }
111 
112     std::lock_guard<std::mutex> lock(mutex_);
113     auto goalCallback = callbackInfoMap_.find(pid);
114     if (goalCallback == callbackInfoMap_.end()) {
115         DLP_LOG_ERROR(LABEL, "can not find pid:%{public}d callback", pid);
116         result = false;
117         return DLP_CALLBACK_PARAM_INVALID;
118     }
119     if (callbackDeathRecipient_ != nullptr && goalCallback->second.callbackObject_ != nullptr) {
120         goalCallback->second.callbackObject_->RemoveDeathRecipient(callbackDeathRecipient_);
121     }
122     goalCallback->second.callbackObject_ = nullptr;
123     callbackInfoMap_.erase(goalCallback);
124     result = true;
125     DLP_LOG_INFO(LABEL, "callbackInfo RemoveCallback succuss");
126     return DLP_OK;
127 }
128 
ExecuteCallbackAsync(const DlpSandboxInfo & dlpSandboxInfo)129 void DlpSandboxChangeCallbackManager::ExecuteCallbackAsync(const DlpSandboxInfo &dlpSandboxInfo)
130 {
131     std::map<int32_t, DlpSandboxChangeCallbackRecord>::iterator goalCallback;
132     {
133         std::lock_guard<std::mutex> lock(mutex_);
134         goalCallback = callbackInfoMap_.find(dlpSandboxInfo.pid);
135         if (goalCallback == callbackInfoMap_.end()) {
136             DLP_LOG_ERROR(LABEL, "can not find pid:%{public}d callback", dlpSandboxInfo.pid);
137             return;
138         }
139     }
140     auto callbackStart = [&goalCallback, &dlpSandboxInfo]() {
141         std::string name = "DlpCallback";
142         pthread_setname_np(pthread_self(), name.substr(0, MAX_PTHREAD_NAME_LEN).c_str());
143         std::vector<sptr<IRemoteObject>> list;
144         auto callback = iface_cast<IDlpSandboxStateChangeCallback>(goalCallback->second.callbackObject_);
145         if (callback != nullptr) {
146             DLP_LOG_INFO(LABEL, "callback excute");
147             DlpSandboxCallbackInfo resInfo;
148             resInfo.appIndex = dlpSandboxInfo.appIndex;
149             resInfo.bundleName = dlpSandboxInfo.bundleName;
150             callback->DlpSandboxStateChangeCallback(resInfo);
151         }
152     };
153     DLP_LOG_INFO(LABEL, "Waiting for the callback execution complete...");
154     std::packaged_task<void()> callbackTask(callbackStart);
155     std::future<void> fut = callbackTask.get_future();
156     std::make_unique<std::thread>(std::move(callbackTask))->detach();
157 
158     DLP_LOG_INFO(LABEL, "Waiting for the callback execution complete...");
159     std::future_status status = fut.wait_for(std::chrono::seconds(MAX_TIMEOUT_SEC));
160     if (status == std::future_status::timeout) {
161         DLP_LOG_INFO(LABEL, "callbackTask callback execution timeout");
162     }
163     DLP_LOG_INFO(LABEL, "The callback execution is complete");
164 }
165 } // namespace DlpPermission
166 } // namespace Security
167 } // namespace OHOS
168