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 "token_modify_notifier.h"
17 
18 #include "accesstoken_callback_proxys.h"
19 #include "accesstoken_id_manager.h"
20 #include "accesstoken_info_manager.h"
21 #include "accesstoken_log.h"
22 #include "access_token_error.h"
23 #include "hap_token_info.h"
24 #include "hap_token_info_inner.h"
25 #include "libraryloader.h"
26 #include "token_sync_kit_loader.h"
27 
28 namespace OHOS {
29 namespace Security {
30 namespace AccessToken {
31 namespace {
32 std::recursive_mutex g_instanceMutex;
33 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "TokenModifyNotifier"};
34 }
35 
36 #ifdef RESOURCESCHEDULE_FFRT_ENABLE
TokenModifyNotifier()37 TokenModifyNotifier::TokenModifyNotifier() : hasInited_(false), curTaskNum_(0) {}
38 #else
TokenModifyNotifier()39 TokenModifyNotifier::TokenModifyNotifier() : hasInited_(false), notifyTokenWorker_("TokenModify") {}
40 #endif
41 
~TokenModifyNotifier()42 TokenModifyNotifier::~TokenModifyNotifier()
43 {
44     if (!hasInited_) {
45         return;
46     }
47 #ifndef RESOURCESCHEDULE_FFRT_ENABLE
48     this->notifyTokenWorker_.Stop();
49 #endif
50     this->hasInited_ = false;
51 }
52 
AddHapTokenObservation(AccessTokenID tokenID)53 void TokenModifyNotifier::AddHapTokenObservation(AccessTokenID tokenID)
54 {
55     if (AccessTokenIDManager::GetInstance().GetTokenIdType(tokenID) != TOKEN_HAP) {
56         ACCESSTOKEN_LOG_INFO(LABEL, "Observation token is not hap token");
57         return;
58     }
59     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(this->Notifylock_);
60     if (observationSet_.count(tokenID) <= 0) {
61         observationSet_.insert(tokenID);
62     }
63 }
64 
NotifyTokenDelete(AccessTokenID tokenID)65 void TokenModifyNotifier::NotifyTokenDelete(AccessTokenID tokenID)
66 {
67     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(this->Notifylock_);
68     if (observationSet_.count(tokenID) <= 0) {
69         ACCESSTOKEN_LOG_DEBUG(LABEL, "Hap token is not observed");
70         return;
71     }
72     observationSet_.erase(tokenID);
73     deleteTokenList_.emplace_back(tokenID);
74     NotifyTokenChangedIfNeed();
75 }
76 
NotifyTokenModify(AccessTokenID tokenID)77 void TokenModifyNotifier::NotifyTokenModify(AccessTokenID tokenID)
78 {
79     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(this->Notifylock_);
80     if (observationSet_.count(tokenID) <= 0) {
81         ACCESSTOKEN_LOG_DEBUG(LABEL, "Hap token is not observed");
82         return;
83     }
84     modifiedTokenList_.emplace_back(tokenID);
85     NotifyTokenChangedIfNeed();
86 }
87 
GetInstance()88 TokenModifyNotifier& TokenModifyNotifier::GetInstance()
89 {
90     static TokenModifyNotifier* instance = nullptr;
91     if (instance == nullptr) {
92         std::lock_guard<std::recursive_mutex> lock(g_instanceMutex);
93         if (instance == nullptr) {
94             instance = new TokenModifyNotifier();
95         }
96     }
97 
98     if (!instance->hasInited_) {
99         Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(instance->initLock_);
100         if (!instance->hasInited_) {
101 #ifndef RESOURCESCHEDULE_FFRT_ENABLE
102             instance->notifyTokenWorker_.Start(1);
103 #endif
104             instance->hasInited_ = true;
105         }
106     }
107 
108     return *instance;
109 }
110 
NotifyTokenSyncTask()111 void TokenModifyNotifier::NotifyTokenSyncTask()
112 {
113     ACCESSTOKEN_LOG_INFO(LABEL, "Called!");
114 
115     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(this->Notifylock_);
116     LibraryLoader loader(TOKEN_SYNC_LIBPATH);
117     TokenSyncKitInterface* tokenSyncKit = loader.GetObject<TokenSyncKitInterface>();
118     if (tokenSyncKit == nullptr) {
119         ACCESSTOKEN_LOG_ERROR(LABEL, "Dlopen libtokensync_sdk failed.");
120         return;
121     }
122     for (AccessTokenID deleteToken : deleteTokenList_) {
123         if (tokenSyncCallbackObject_ != nullptr) {
124             tokenSyncCallbackObject_->DeleteRemoteHapTokenInfo(deleteToken);
125         }
126         tokenSyncKit->DeleteRemoteHapTokenInfo(deleteToken);
127     }
128 
129     for (AccessTokenID modifyToken : modifiedTokenList_) {
130         HapTokenInfoForSync hapSync;
131         int ret = AccessTokenInfoManager::GetInstance().GetHapTokenSync(modifyToken, hapSync);
132         if (ret != RET_SUCCESS) {
133             ACCESSTOKEN_LOG_ERROR(LABEL, "The hap token 0x%{public}x need to sync is not found!", modifyToken);
134             continue;
135         }
136         if (tokenSyncCallbackObject_ != nullptr) {
137             tokenSyncCallbackObject_->UpdateRemoteHapTokenInfo(hapSync);
138         }
139         tokenSyncKit->UpdateRemoteHapTokenInfo(hapSync);
140     }
141     deleteTokenList_.clear();
142     modifiedTokenList_.clear();
143 
144     ACCESSTOKEN_LOG_INFO(LABEL, "Over!");
145 }
146 
GetRemoteHapTokenInfo(const std::string & deviceID,AccessTokenID tokenID)147 int32_t TokenModifyNotifier::GetRemoteHapTokenInfo(const std::string& deviceID, AccessTokenID tokenID)
148 {
149     if (tokenSyncCallbackObject_ != nullptr) {
150         Utils::UniqueReadGuard<Utils::RWLock> infoGuard(this->Notifylock_);
151         int32_t ret = tokenSyncCallbackObject_->GetRemoteHapTokenInfo(deviceID, tokenID);
152         if (ret != TOKEN_SYNC_OPENSOURCE_DEVICE) {
153             return ret;
154         }
155     }
156 
157     LibraryLoader loader(TOKEN_SYNC_LIBPATH);
158     TokenSyncKitInterface* tokenSyncKit = loader.GetObject<TokenSyncKitInterface>();
159     if (tokenSyncKit == nullptr) {
160         ACCESSTOKEN_LOG_ERROR(LABEL, "Dlopen libtokensync_sdk failed.");
161         return ERR_LOAD_SO_FAILED;
162     }
163     return tokenSyncKit->GetRemoteHapTokenInfo(deviceID, tokenID);
164 }
165 
RegisterTokenSyncCallback(const sptr<IRemoteObject> & callback)166 int32_t TokenModifyNotifier::RegisterTokenSyncCallback(const sptr<IRemoteObject>& callback)
167 {
168     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(this->Notifylock_);
169     tokenSyncCallbackObject_ = new TokenSyncCallbackProxy(callback);
170     tokenSyncCallbackDeathRecipient_ = sptr<TokenSyncCallbackDeathRecipient>::MakeSptr();
171     callback->AddDeathRecipient(tokenSyncCallbackDeathRecipient_);
172     ACCESSTOKEN_LOG_INFO(LABEL, "Register token sync callback successful.");
173     return ERR_OK;
174 }
175 
UnRegisterTokenSyncCallback()176 int32_t TokenModifyNotifier::UnRegisterTokenSyncCallback()
177 {
178     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(this->Notifylock_);
179     if (tokenSyncCallbackObject_ != nullptr && tokenSyncCallbackDeathRecipient_ != nullptr) {
180         tokenSyncCallbackObject_->AsObject()->RemoveDeathRecipient(tokenSyncCallbackDeathRecipient_);
181     }
182     tokenSyncCallbackObject_ = nullptr;
183     tokenSyncCallbackDeathRecipient_ = nullptr;
184     ACCESSTOKEN_LOG_INFO(LABEL, "Unregister token sync callback successful.");
185     return ERR_OK;
186 }
187 
188 #ifdef RESOURCESCHEDULE_FFRT_ENABLE
GetCurTaskNum()189 int32_t TokenModifyNotifier::GetCurTaskNum()
190 {
191     return curTaskNum_.load();
192 }
193 
AddCurTaskNum()194 void TokenModifyNotifier::AddCurTaskNum()
195 {
196     ACCESSTOKEN_LOG_INFO(LABEL, "Add task!");
197     curTaskNum_++;
198 }
199 
ReduceCurTaskNum()200 void TokenModifyNotifier::ReduceCurTaskNum()
201 {
202     ACCESSTOKEN_LOG_INFO(LABEL, "Reduce task!");
203     curTaskNum_--;
204 }
205 #endif
206 
NotifyTokenChangedIfNeed()207 void TokenModifyNotifier::NotifyTokenChangedIfNeed()
208 {
209 #ifdef RESOURCESCHEDULE_FFRT_ENABLE
210     if (GetCurTaskNum() > 1) {
211         ACCESSTOKEN_LOG_INFO(LABEL, "Has notify task! taskNum is %{public}d.", GetCurTaskNum());
212         return;
213     }
214 
215     std::string taskName = "TokenModify";
216     auto tokenModify = []() {
217         TokenModifyNotifier::GetInstance().NotifyTokenSyncTask();
218         TokenModifyNotifier::GetInstance().ReduceCurTaskNum();
219     };
220     ffrt::submit(tokenModify, {}, {}, ffrt::task_attr().qos(ffrt::qos_default).name(taskName.c_str()));
221     AddCurTaskNum();
222 #else
223     if (notifyTokenWorker_.GetCurTaskNum() > 1) {
224         ACCESSTOKEN_LOG_INFO(LABEL, " has notify task! taskNum is %{public}zu.", notifyTokenWorker_.GetCurTaskNum());
225         return;
226     }
227 
228     notifyTokenWorker_.AddTask([]() {
229         TokenModifyNotifier::GetInstance().NotifyTokenSyncTask();
230     });
231 #endif
232 }
233 } // namespace AccessToken
234 } // namespace Security
235 } // namespace OHOS
236