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 "co_auth_service.h"
17 
18 #include <cinttypes>
19 #include <thread>
20 
21 #include "string_ex.h"
22 
23 #include "device_manager_util.h"
24 #include "executor_messenger_service.h"
25 #include "hdi_message_callback_service.h"
26 #include "hdi_wrapper.h"
27 #include "hisysevent_adapter.h"
28 #include "iam_logger.h"
29 #include "iam_ptr.h"
30 #include "iam_para2str.h"
31 #include "ipc_common.h"
32 #include "iam_check.h"
33 #include "iam_time.h"
34 #include "iam_common_defines.h"
35 #include "ipc_skeleton.h"
36 #include "parameter.h"
37 #include "relative_timer.h"
38 #include "remote_connect_manager.h"
39 #include "resource_node_pool.h"
40 #include "template_cache_manager.h"
41 #include "remote_msg_util.h"
42 #include "xcollie_helper.h"
43 
44 #define LOG_TAG "USER_AUTH_SA"
45 
46 namespace OHOS {
47 namespace UserIam {
48 namespace UserAuth {
49 namespace {
50 const bool REGISTER_RESULT = SystemAbility::MakeAndRegisterAbility(CoAuthService::GetInstance().get());
51 } // namespace
52 
53 constexpr int32_t USERIAM_IPC_THREAD_NUM = 4;
54 std::shared_ptr<CoAuthService> CoAuthService::instance_ = nullptr;
55 
GetInstance()56 std::shared_ptr<CoAuthService> CoAuthService::GetInstance()
57 {
58     static std::recursive_mutex mutex;
59     if (instance_ == nullptr) {
60         std::lock_guard<std::recursive_mutex> guard(mutex);
61         if (instance_ == nullptr) {
62             instance_ = Common::MakeShared<CoAuthService>();
63             if (instance_ == nullptr) {
64                 IAM_LOGE("make share failed");
65             }
66         }
67     }
68     return instance_;
69 }
70 
CoAuthService()71 CoAuthService::CoAuthService() : SystemAbility(SUBSYS_USERIAM_SYS_ABILITY_AUTHEXECUTORMGR, true)
72 {
73     IAM_LOGI("CoAuthService init");
74 }
75 
OnStart()76 void CoAuthService::OnStart()
77 {
78     static uint32_t timerId = 0;
79     std::lock_guard<std::recursive_mutex> guard(mutex_);
80     IAM_LOGI("Start service");
81     IPCSkeleton::SetMaxWorkThreadNum(USERIAM_IPC_THREAD_NUM);
82     if (!Publish(this)) {
83         IAM_LOGE("Failed to publish service");
84         return;
85     }
86 
87     if (timerId != 0) {
88         RelativeTimer::GetInstance().Unregister(timerId);
89     }
90     timerId = RelativeTimer::GetInstance().Register(Init, 0);
91     RegisterAccessTokenListener();
92 }
93 
OnStop()94 void CoAuthService::OnStop()
95 {
96     IAM_LOGI("Stop service");
97     UnRegisterAccessTokenListener();
98 }
99 
SetIsReady(bool isReady)100 void CoAuthService::SetIsReady(bool isReady)
101 {
102     std::lock_guard<std::recursive_mutex> guard(mutex_);
103     isReady_ = isReady;
104     IAM_LOGI("Set isReady %{public}d", isReady);
105 }
106 
SetAccessTokenReady(bool isReady)107 void CoAuthService::SetAccessTokenReady(bool isReady)
108 {
109     std::lock_guard<std::recursive_mutex> guard(mutex_);
110     accessTokenReady_ = isReady;
111     IAM_LOGI("Set accesstoken ready %{public}d", accessTokenReady_);
112 }
113 
IsFwkReady()114 bool CoAuthService::IsFwkReady()
115 {
116     std::lock_guard<std::recursive_mutex> guard(mutex_);
117     return isReady_ && accessTokenReady_;
118 }
119 
AddExecutorDeathRecipient(uint64_t executorIndex,AuthType authType,std::shared_ptr<ExecutorCallbackInterface> callback)120 void CoAuthService::AddExecutorDeathRecipient(uint64_t executorIndex, AuthType authType,
121     std::shared_ptr<ExecutorCallbackInterface> callback)
122 {
123     IF_FALSE_LOGE_AND_RETURN(callback != nullptr);
124     auto obj = callback->AsObject();
125     IF_FALSE_LOGE_AND_RETURN(obj != nullptr);
126 
127     obj->AddDeathRecipient(new (std::nothrow) IpcCommon::PeerDeathRecipient([executorIndex, authType]() {
128         IAM_LOGE("executorCallback is down");
129         auto weakNode = ResourceNodePool::Instance().Select(executorIndex);
130         auto sharedNode = weakNode.lock();
131         if (sharedNode != nullptr) {
132             auto result = ResourceNodePool::Instance().Delete(executorIndex);
133             IAM_LOGI("delete executor %{public}s, executorIndex is ****%{public}hx authType is %{public}d "
134                 "executorRole is %{public}d", (result ? "succ" : "failed"), static_cast<uint16_t>(executorIndex),
135                 sharedNode->GetAuthType(), sharedNode->GetExecutorRole());
136         }
137 
138         std::string executorDesc = "executor, type " + std::to_string(authType);
139         UserIam::UserAuth::ReportSystemFault(Common::GetNowTimeString(), executorDesc);
140         IAM_LOGI("executorCallback is down processed");
141     }));
142 }
143 
ExecutorRegister(const ExecutorRegisterInfo & info,sptr<ExecutorCallbackInterface> & callback)144 uint64_t CoAuthService::ExecutorRegister(const ExecutorRegisterInfo &info, sptr<ExecutorCallbackInterface> &callback)
145 {
146     IAM_LOGI("register resource node begin");
147     Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
148     if (callback == nullptr) {
149         IAM_LOGE("executor callback is nullptr");
150         return INVALID_EXECUTOR_INDEX;
151     }
152 
153     std::lock_guard<std::recursive_mutex> guard(mutex_);
154     if (!IsFwkReady()) {
155         IAM_LOGE("framework is not ready");
156         return INVALID_EXECUTOR_INDEX;
157     }
158 
159     if (!IpcCommon::CheckPermission(*this, ACCESS_AUTH_RESPOOL)) {
160         IAM_LOGE("failed to check permission");
161         return INVALID_EXECUTOR_INDEX;
162     }
163 
164     std::vector<uint64_t> templateIdList;
165     std::vector<uint8_t> fwkPublicKey;
166     auto executorCallback = Common::SptrToStdSharedPtr<ExecutorCallbackInterface>(callback);
167     auto resourceNode = ResourceNode::MakeNewResource(info, executorCallback, templateIdList, fwkPublicKey);
168     if (resourceNode == nullptr) {
169         IAM_LOGE("create resource node failed");
170         return INVALID_EXECUTOR_INDEX;
171     }
172     if (!ResourceNodePool::Instance().Insert(resourceNode)) {
173         IAM_LOGE("insert resource node failed");
174         return INVALID_EXECUTOR_INDEX;
175     }
176 
177     uint64_t executorIndex = resourceNode->GetExecutorIndex();
178     auto handler = ThreadHandler::GetSingleThreadInstance();
179     std::weak_ptr<ResourceNode> weakNode = resourceNode;
180     IF_FALSE_LOGE_AND_RETURN_VAL(handler != nullptr, GENERAL_ERROR);
181     handler->PostTask([executorCallback, fwkPublicKey, templateIdList, weakNode, executorIndex]() {
182         auto resourceNode = weakNode.lock();
183         IF_FALSE_LOGE_AND_RETURN(resourceNode != nullptr);
184         sptr<ExecutorMessengerInterface> messenger = ExecutorMessengerService::GetInstance();
185         executorCallback->OnMessengerReady(messenger, fwkPublicKey, templateIdList);
186         IAM_LOGI("register successful, executorType is %{public}d, executorRole is %{public}d, "
187             "executorIndex is ****%{public}hx",
188             resourceNode->GetAuthType(), resourceNode->GetExecutorRole(), static_cast<uint16_t>(executorIndex));
189         AddExecutorDeathRecipient(executorIndex, resourceNode->GetAuthType(), executorCallback);
190         IAM_LOGI("update template cache after register success");
191         TemplateCacheManager::GetInstance().UpdateTemplateCache(resourceNode->GetAuthType());
192     });
193     return executorIndex;
194 }
195 
ExecutorUnregister(uint64_t executorIndex)196 void CoAuthService::ExecutorUnregister(uint64_t executorIndex)
197 {
198     IAM_LOGI("delete resource node begin");
199     Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
200     std::lock_guard<std::recursive_mutex> guard(mutex_);
201     if (!IsFwkReady()) {
202         IAM_LOGE("framework is not ready");
203         return;
204     }
205 
206     if (!IpcCommon::CheckPermission(*this, ACCESS_AUTH_RESPOOL)) {
207         IAM_LOGE("failed to check permission");
208         return;
209     }
210 
211     if (!ResourceNodePool::Instance().Delete(executorIndex)) {
212         IAM_LOGE("delete resource node failed");
213         return;
214     }
215     IAM_LOGI("delete resource node success, executorIndex is ****%{public}hx", static_cast<uint16_t>(executorIndex));
216 }
217 
Init()218 void CoAuthService::Init()
219 {
220     auto instance = CoAuthService::GetInstance();
221     if (instance == nullptr) {
222         IAM_LOGE("instance is nullptr");
223         return;
224     }
225     instance->AuthServiceInit();
226 }
227 
AuthServiceInit()228 void CoAuthService::AuthServiceInit()
229 {
230     auto hdi = HdiWrapper::GetHdiRemoteObjInstance();
231     if (hdi) {
232         hdi->AddDeathRecipient(new (std::nothrow) IpcCommon::PeerDeathRecipient([]() {
233             IAM_LOGE("user auth host is dead");
234             ResourceNodePool::Instance().DeleteAll();
235             RelativeTimer::GetInstance().Register(Init, DEFER_TIME);
236             auto instance = CoAuthService::GetInstance();
237             if (instance != nullptr) {
238                 instance->SetIsReady(false);
239             }
240             UserIam::UserAuth::ReportSystemFault(Common::GetNowTimeString(), "user_auth_hdi host");
241         }));
242 
243         std::string localUdid;
244         bool getLocalUdidRet = DeviceManagerUtil::GetInstance().GetLocalDeviceUdid(localUdid);
245         IF_FALSE_LOGE_AND_RETURN(getLocalUdidRet);
246         auto service = HdiWrapper::GetHdiInstance();
247         IF_FALSE_LOGE_AND_RETURN(service != nullptr);
248         int32_t initRet = service->Init(localUdid);
249         IF_FALSE_LOGE_AND_RETURN(initRet == HDF_SUCCESS);
250         auto callbackService = HdiMessageCallbackService::GetInstance();
251         IF_FALSE_LOGE_AND_RETURN(callbackService != nullptr);
252         callbackService->OnHdiConnect();
253         SetIsReady(true);
254         NotifyFwkReady();
255     } else {
256         RelativeTimer::GetInstance().Register(Init, DEFER_TIME);
257     }
258 }
259 
Dump(int fd,const std::vector<std::u16string> & args)260 int CoAuthService::Dump(int fd, const std::vector<std::u16string> &args)
261 {
262     IAM_LOGI("start");
263     if (fd < 0) {
264         IAM_LOGE("invalid parameters");
265         dprintf(fd, "Invalid parameters.\n");
266         return INVALID_PARAMETERS;
267     }
268     std::string arg0 = (args.empty() ? "" : Str16ToStr8(args[0]));
269     if (arg0.empty() || arg0.compare("-h") == 0) {
270         dprintf(fd, "Usage:\n");
271         dprintf(fd, "      -h: command help.\n");
272         dprintf(fd, "      -l: resource pool dump.\n");
273         return SUCCESS;
274     }
275     if (arg0.compare("-l") == 0) {
276         ResourceNodePool::Instance().Enumerate([fd](const std::weak_ptr<ResourceNode> &node) {
277             auto nodeTmp = node.lock();
278             if (nodeTmp != nullptr) {
279                 dprintf(fd, "ExecutorIndex is: %" PRIx64 ".\n", nodeTmp->GetExecutorIndex());
280                 dprintf(fd, "ExecutorType is: %s.\n", Common::AuthTypeToStr(nodeTmp->GetAuthType()));
281                 dprintf(fd, "ExecutorRole is: %s.\n", Common::ExecutorRoleToStr(nodeTmp->GetExecutorRole()));
282             }
283         });
284         return SUCCESS;
285     }
286     IAM_LOGE("invalid option");
287     dprintf(fd, "Invalid option\n");
288     return GENERAL_ERROR;
289 }
290 
RegisterAccessTokenListener()291 ResultCode CoAuthService::RegisterAccessTokenListener()
292 {
293     IAM_LOGD("start.");
294     std::lock_guard<std::recursive_mutex> lock(mutex_);
295     if (accessTokenListener_ != nullptr) {
296         IAM_LOGI("accessTokenListener_ is not nullptr.");
297         return SUCCESS;
298     }
299 
300     accessTokenListener_ = SystemAbilityListener::Subscribe("accesstoken_service", ACCESS_TOKEN_MANAGER_SERVICE_ID,
301         []() {
302             auto instance = CoAuthService::GetInstance();
303             if (instance == nullptr) {
304                 IAM_LOGE("CoAuthService instance is nullptr.");
305                 return;
306             }
307             instance->SetAccessTokenReady(true);
308             instance->NotifyFwkReady();
309         },
310         nullptr);
311     if (accessTokenListener_ == nullptr) {
312         IAM_LOGE("accessTokenListener_ is nullptr.");
313         return GENERAL_ERROR;
314     }
315 
316     IAM_LOGI("RegisterAccessTokenListener success.");
317     return SUCCESS;
318 }
319 
UnRegisterAccessTokenListener()320 ResultCode CoAuthService::UnRegisterAccessTokenListener()
321 {
322     IAM_LOGD("start.");
323     std::lock_guard<std::recursive_mutex> lock(mutex_);
324     if (accessTokenListener_ == nullptr) {
325         IAM_LOGI("accessTokenListener_ is nullptr.");
326         return SUCCESS;
327     }
328 
329     int32_t ret = SystemAbilityListener::UnSubscribe(ACCESS_TOKEN_MANAGER_SERVICE_ID, accessTokenListener_);
330     if (ret != SUCCESS) {
331         IAM_LOGE("UnSubscribe service fail.");
332         return GENERAL_ERROR;
333     }
334 
335     accessTokenListener_ = nullptr;
336     IAM_LOGI("UnRegisterAccessTokenListener success.");
337     return SUCCESS;
338 }
339 
NotifyFwkReady()340 void CoAuthService::NotifyFwkReady()
341 {
342     IAM_LOGD("start.");
343     if (IsFwkReady()) {
344         IAM_LOGI("set fwk ready parameter begin");
345         SetParameter("bootevent.useriam.fwkready", "false");
346         SetParameter("bootevent.useriam.fwkready", "true");
347         IAM_LOGI("set fwk ready parameter success");
348     }
349 }
350 } // namespace UserAuth
351 } // namespace UserIam
352 } // namespace OHOS