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 "template_cache_manager.h"
17 
18 #include <mutex>
19 
20 #include "os_account_manager.h"
21 #include "iservice_registry.h"
22 #include "system_ability_definition.h"
23 #include "system_ability_status_change_stub.h"
24 
25 #include "iam_check.h"
26 #include "iam_logger.h"
27 #include "iam_ptr.h"
28 #include "context_pool.h"
29 #include "resource_node_pool.h"
30 #include "resource_node_utils.h"
31 #include "user_idm_database.h"
32 #include "thread_handler.h"
33 
34 #define LOG_TAG "USER_AUTH_SA"
35 namespace OHOS {
36 namespace UserIam {
37 namespace UserAuth {
38 namespace {
GetCurrentUserId()39 int32_t GetCurrentUserId()
40 {
41     std::vector<int32_t> ids;
42     ErrCode queryRet = AccountSA::OsAccountManager::QueryActiveOsAccountIds(ids);
43     if (queryRet != ERR_OK || ids.empty()) {
44         IAM_LOGE("failed to query active account id ret %{public}d count %{public}zu",
45             queryRet, ids.size());
46         return INVALID_USER_ID;
47     }
48     return ids.front();
49 }
50 }
51 using OsAccountSubscriber = AccountSA::OsAccountSubscriber;
52 using OsAccountSubscribeInfo = AccountSA::OsAccountSubscribeInfo;
53 using OS_ACCOUNT_SUBSCRIBE_TYPE = AccountSA::OS_ACCOUNT_SUBSCRIBE_TYPE;
54 
55 class ServiceStatusListener : public OHOS::SystemAbilityStatusChangeStub, public NoCopyable {
56 public:
57     static sptr<ServiceStatusListener> GetInstance();
58     static void Subscribe();
59 
60     void OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId) override;
61     void OnRemoveSystemAbility(int32_t systemAbilityId, const std::string &deviceId) override;
62 
63 private:
ServiceStatusListener()64     ServiceStatusListener() {};
~ServiceStatusListener()65     ~ServiceStatusListener() override {};
66 };
67 
68 class OsAccountIdSubscriber : public OsAccountSubscriber, public NoCopyable {
69 public:
70     explicit OsAccountIdSubscriber(const OsAccountSubscribeInfo &subscribeInfo);
71     ~OsAccountIdSubscriber() = default;
72 
73     static std::shared_ptr<OsAccountIdSubscriber> GetInstance();
74     static void Subscribe();
75     static void Unsubscribe();
76     void OnAccountsChanged(const int& id) override;
77 
78 private:
79     std::shared_ptr<ThreadHandler> threadHandler_;
80 };
81 
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)82 void ServiceStatusListener::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
83 {
84     if (systemAbilityId != SUBSYS_ACCOUNT_SYS_ABILITY_ID_BEGIN) {
85         return;
86     }
87 
88     IAM_LOGI("os account service added");
89     OsAccountIdSubscriber::Subscribe();
90     IAM_LOGI("os account service add process finish");
91 }
92 
OnRemoveSystemAbility(int32_t systemAbilityId,const std::string & deviceId)93 void ServiceStatusListener::OnRemoveSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
94 {
95     if (systemAbilityId != SUBSYS_ACCOUNT_SYS_ABILITY_ID_BEGIN) {
96         return;
97     }
98 
99     IAM_LOGI("os account service removed");
100     OsAccountIdSubscriber::Unsubscribe();
101     ContextPool::Instance().CancelAll();
102     IAM_LOGI("os account service remove process finish");
103 }
104 
GetInstance()105 sptr<ServiceStatusListener> ServiceStatusListener::GetInstance()
106 {
107     static sptr<ServiceStatusListener> listener(new (std::nothrow) ServiceStatusListener());
108     if (listener == nullptr) {
109         IAM_LOGE("ServiceStatusListener is null");
110     }
111     return listener;
112 }
113 
Subscribe()114 void ServiceStatusListener::Subscribe()
115 {
116     auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
117     if (sam == nullptr) {
118         IAM_LOGE("failed to get SA manager");
119         return;
120     }
121 
122     auto instance = GetInstance();
123     IF_FALSE_LOGE_AND_RETURN(instance != NULL);
124 
125     int32_t ret = sam->SubscribeSystemAbility(SUBSYS_ACCOUNT_SYS_ABILITY_ID_BEGIN, instance);
126     if (ret != ERR_OK) {
127         IAM_LOGE("failed to subscribe os account service status");
128         return;
129     }
130 
131     IAM_LOGI("subscribe os account SA service status success");
132 }
133 
OsAccountIdSubscriber(const OsAccountSubscribeInfo & subscribeInfo)134 OsAccountIdSubscriber::OsAccountIdSubscriber(const OsAccountSubscribeInfo &subscribeInfo)
135     : OsAccountSubscriber(subscribeInfo),
136       threadHandler_(ThreadHandler::GetSingleThreadInstance())
137 {}
138 
Subscribe()139 void OsAccountIdSubscriber::Subscribe()
140 {
141     IAM_LOGI("start");
142     auto instance = GetInstance();
143     IF_FALSE_LOGE_AND_RETURN(instance != NULL);
144 
145     ErrCode errCode = AccountSA::OsAccountManager::SubscribeOsAccount(instance);
146     if (errCode != ERR_OK) {
147         IAM_LOGE("subscribe fail, errCode = %{public}d", errCode);
148         return;
149     }
150 
151     int32_t userId = GetCurrentUserId();
152     if (userId == INVALID_USER_ID) {
153         IAM_LOGE("GetCurrentUserId fail");
154         return;
155     }
156     TemplateCacheManager::GetInstance().ProcessUserIdChange(userId);
157     IAM_LOGI("subscribe success");
158 }
159 
Unsubscribe()160 void OsAccountIdSubscriber::Unsubscribe()
161 {
162     auto instance = GetInstance();
163     IF_FALSE_LOGE_AND_RETURN(instance != NULL);
164 
165     ErrCode errCode = AccountSA::OsAccountManager::UnsubscribeOsAccount(instance);
166     if (errCode != ERR_OK) {
167         IAM_LOGE("unsubscribe fail, errCode = %{public}d", errCode);
168         return;
169     }
170     IAM_LOGI("unsubscribe success");
171 }
172 
OnAccountsChanged(const int & id)173 void OsAccountIdSubscriber::OnAccountsChanged(const int& id)
174 {
175     IAM_LOGI("OnAccountsChanged %{public}d", id);
176     if (threadHandler_ == nullptr) {
177         IAM_LOGE("threadHandler_ not set");
178         return;
179     }
180 
181     threadHandler_->PostTask([id]() {
182         IAM_LOGI("task process begin");
183         TemplateCacheManager::GetInstance().ProcessUserIdChange(id);
184         IAM_LOGI("task process end");
185     });
186 }
187 
GetInstance()188 std::shared_ptr<OsAccountIdSubscriber> OsAccountIdSubscriber::GetInstance()
189 {
190     OsAccountSubscribeInfo subscribeInfo;
191     subscribeInfo.SetOsAccountSubscribeType(OS_ACCOUNT_SUBSCRIBE_TYPE::ACTIVED);
192 
193     static auto subscriber = Common::MakeShared<OsAccountIdSubscriber>(subscribeInfo);
194     if (subscriber == nullptr) {
195         IAM_LOGE("OsAccountIdSubscriber is null");
196     }
197     return subscriber;
198 }
199 
TemplateCacheManager()200 TemplateCacheManager::TemplateCacheManager()
201 {
202     ServiceStatusListener::Subscribe();
203 }
204 
GetInstance()205 TemplateCacheManager &TemplateCacheManager::GetInstance()
206 {
207     static TemplateCacheManager templateCacheManager;
208     return templateCacheManager;
209 }
210 
ProcessUserIdChange(const int newUserId)211 void TemplateCacheManager::ProcessUserIdChange(const int newUserId)
212 {
213     {
214         std::lock_guard<std::recursive_mutex> lock(recursiveMutex_);
215         if (newUserId == currUserId_) {
216             IAM_LOGE("same userId %{public}d", newUserId);
217             return;
218         }
219 
220         IAM_LOGI("begin");
221         currUserId_ = newUserId;
222     }
223     UpdateTemplateCache(FACE);
224     UpdateTemplateCache(FINGERPRINT);
225     IAM_LOGI("done");
226     return;
227 }
228 
UpdateTemplateCache(AuthType authType)229 void TemplateCacheManager::UpdateTemplateCache(AuthType authType)
230 {
231     IAM_LOGI("start");
232     int32_t currUserId = 0;
233     {
234         std::lock_guard<std::recursive_mutex> lock(recursiveMutex_);
235         currUserId = currUserId_;
236     }
237 
238     IF_FALSE_LOGE_AND_RETURN(currUserId != INVALID_USER_ID);
239     if (authType != FACE && authType != FINGERPRINT) {
240         IAM_LOGI("this auth type is not cached");
241         return;
242     }
243 
244     std::vector<std::shared_ptr<CredentialInfoInterface>> credentialInfos;
245     int32_t ret = UserIdmDatabase::Instance().GetCredentialInfo(currUserId, authType, credentialInfos);
246     if (ret != SUCCESS) {
247         IAM_LOGE("get credential fail, ret:%{public}d, userId:%{public}d, authType:%{public}d", ret,
248             currUserId, authType);
249         return;
250     }
251 
252     if (credentialInfos.empty()) {
253         IAM_LOGI("user %{public}d has no credential type %{public}d", currUserId, authType);
254         ResourceNodePool::Instance().Enumerate([authType](const std::weak_ptr<ResourceNode> &node) {
255             auto nodeTmp = node.lock();
256             IF_FALSE_LOGE_AND_RETURN(nodeTmp != nullptr);
257 
258             if (nodeTmp->GetAuthType() != authType) {
259                 return;
260             }
261             IAM_LOGI("clear cached template for type %{public}d", authType);
262             ResourceNodeUtils::SetCachedTemplates(nodeTmp->GetExecutorIndex(),
263                 std::vector<std::shared_ptr<CredentialInfoInterface>>());
264         });
265         return;
266     }
267 
268     IAM_LOGI("user %{public}d type %{public}d credential info size %{public}zu",
269         currUserId, authType, credentialInfos.size());
270     std::map<uint64_t, std::vector<std::shared_ptr<CredentialInfoInterface>>> id2Cred;
271     ResultCode result = ResourceNodeUtils::ClassifyCredInfoByExecutor(credentialInfos, id2Cred);
272     IF_FALSE_LOGE_AND_RETURN(result == SUCCESS);
273 
274     for (auto const &pair : id2Cred) {
275         ResourceNodeUtils::SetCachedTemplates(pair.first, pair.second);
276     }
277 }
278 } // namespace UserAuth
279 } // namespace UserIam
280 } // namespace OHOS