1 /*
2  * Copyright (c) 2022 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 "device_security_level_callback_helper.h"
17 
18 #include <cstdint>
19 #include <functional>
20 #include <map>
21 #include <new>
22 #include <utility>
23 
24 #include "hilog/log_cpp.h"
25 #include "idevice_security_level.h"
26 #include "timer.h"
27 
28 #include "device_security_info.h"
29 #include "device_security_level_callback_stub.h"
30 #include "device_security_level_defines.h"
31 
32 namespace OHOS {
33 namespace Security {
34 namespace DeviceSecurityLevel {
35 using namespace OHOS::HiviewDFX;
36 
37 constexpr char TIMER_NAME[] = "DSLM_CALL_TIMER";
38 constexpr uint32_t KEEP_COMPENSATION_LEN = 5;
39 constexpr uint32_t MAX_CALLBACKS_NUM = 128;
40 
DeviceSecurityLevelCallbackHelper()41 DeviceSecurityLevelCallbackHelper::DeviceSecurityLevelCallbackHelper()
42 {
43     auto request = [this](uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) {
44         return this->OnRemoteRequest(code, data, reply, option);
45     };
46     stub_ = new (std::nothrow) DeviceSecurityLevelCallbackStub(request);
47 }
48 
~DeviceSecurityLevelCallbackHelper()49 DeviceSecurityLevelCallbackHelper::~DeviceSecurityLevelCallbackHelper()
50 {
51     stub_ = nullptr;
52 }
53 
Publish(const DeviceIdentify & identity,const ResultCallback & callback,uint32_t keep,sptr<DeviceSecurityLevelCallbackStub> & stub,uint32_t & cookie)54 bool DeviceSecurityLevelCallbackHelper::Publish(const DeviceIdentify &identity, const ResultCallback &callback,
55     uint32_t keep, sptr<DeviceSecurityLevelCallbackStub> &stub, uint32_t &cookie)
56 {
57     if (stub_ == nullptr) {
58         return false;
59     }
60 
61     auto result = holder_.PushCallback(identity, callback, keep, cookie);
62     if (!result) {
63         HILOG_ERROR(LOG_CORE, "DeviceSecurityLevelCallbackHelper::PushCallback failed");
64         return false;
65     }
66 
67     stub = stub_;
68     return true;
69 }
70 
Withdraw(uint32_t cookie)71 bool DeviceSecurityLevelCallbackHelper::Withdraw(uint32_t cookie)
72 {
73     if (cookie == 0) {
74         return false;
75     }
76 
77     auto result = holder_.PopCallback(cookie);
78     if (!result) {
79         HILOG_ERROR(LOG_CORE, "DeviceSecurityLevelCallbackHelper::withdraw failed");
80         return false;
81     }
82     return true;
83 }
84 
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)85 int32_t DeviceSecurityLevelCallbackHelper::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply,
86     MessageOption &option)
87 {
88     if (code == DeviceSecurityLevelCallbackStub::CMD_SET_DEVICE_SECURITY_LEVEL) {
89         auto cookie = data.ReadUint32();
90         auto result = data.ReadUint32();
91         auto level = data.ReadUint32();
92         HILOG_INFO(LOG_CORE, "callback cookie %{public}u, result %{public}u, level %{public}u", cookie, result, level);
93         holder_.PopCallback(cookie, result, level);
94     }
95 
96     return SUCCESS;
97 }
98 
CallbackInfoHolder()99 DeviceSecurityLevelCallbackHelper::CallbackInfoHolder::CallbackInfoHolder() : timer_(TIMER_NAME)
100 {
101     timer_.Setup();
102 }
103 
~CallbackInfoHolder()104 DeviceSecurityLevelCallbackHelper::CallbackInfoHolder::~CallbackInfoHolder()
105 {
106     timer_.Shutdown();
107 }
108 
PushCallback(const DeviceIdentify & identity,const ResultCallback & callback,uint32_t keep,uint32_t & cookie)109 bool DeviceSecurityLevelCallbackHelper::CallbackInfoHolder::PushCallback(const DeviceIdentify &identity,
110     const ResultCallback &callback, uint32_t keep, uint32_t &cookie)
111 {
112     std::lock_guard<std::mutex> lock(mutex_);
113     if (map_.size() > MAX_CALLBACKS_NUM) {
114         HILOG_ERROR(LOG_CORE, "DeviceSecurityLevelCallbackHelper::PushCallback reached max");
115         return false;
116     }
117 
118     cookie = ++generate_;
119     CallbackInfo info = {.identity = identity, .callback = callback, .cookie = cookie};
120     auto result = map_.emplace(generate_, info);
121     if (result.second) {
122         auto deleter = [cookie, this]() { PopCallback(cookie, ERR_TIMEOUT, 0); };
123         keep += KEEP_COMPENSATION_LEN;
124         timer_.Register(deleter, keep * 1000, true); // 1000 millisec
125     }
126     return result.second;
127 }
128 
PopCallback(uint32_t cookie,uint32_t result,uint32_t level)129 bool DeviceSecurityLevelCallbackHelper::CallbackInfoHolder::PopCallback(uint32_t cookie, uint32_t result,
130     uint32_t level)
131 {
132     DeviceIdentify identity;
133     ResultCallback callback;
134     {
135         std::lock_guard<std::mutex> lock(mutex_);
136         auto iter = map_.find(cookie);
137         if (iter == map_.end()) {
138             return false;
139         }
140         identity = iter->second.identity;
141         callback = iter->second.callback;
142         map_.erase(iter);
143     }
144 
145     if (callback != nullptr) {
146         DeviceSecurityInfo *info = new (std::nothrow) DeviceSecurityInfo();
147         if (info != nullptr) {
148             info->magicNum = SECURITY_MAGIC;
149             info->result = result;
150             info->level = level;
151         }
152         callback(&identity, info);
153     }
154 
155     return true;
156 }
PopCallback(uint32_t cookie)157 bool DeviceSecurityLevelCallbackHelper::CallbackInfoHolder::PopCallback(uint32_t cookie)
158 {
159     std::lock_guard<std::mutex> lock(mutex_);
160     auto iter = map_.find(cookie);
161     if (iter == map_.end()) {
162         return false;
163     }
164     map_.erase(iter);
165     return true;
166 }
167 } // namespace DeviceSecurityLevel
168 } // namespace Security
169 } // namespace OHOS
170