• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "inner_app_account_manager.h"
17 
18 #include "ability_manager_adapter.h"
19 #include "account_info.h"
20 #include "account_log_wrapper.h"
21 #include "app_account_authenticator_session.h"
22 #include "app_account_control_manager.h"
23 #include "app_account_subscribe_manager.h"
24 #include "app_account_authorization_extension_callback_service.h"
25 #include "app_account_authorization_extension_stub.h"
26 #include "bundle_manager_adapter.h"
27 
28 namespace OHOS {
29 namespace AccountSA {
InnerAppAccountManager()30 InnerAppAccountManager::InnerAppAccountManager()
31     : controlManager_(AppAccountControlManager::GetInstance()),
32       subscribeManager_(AppAccountSubscribeManager::GetInstance()),
33       sessionManager_(AppAccountAuthenticatorSessionManager::GetInstance())
34 {
35     ACCOUNT_LOGI("Constructed");
36 }
37 
~InnerAppAccountManager()38 InnerAppAccountManager::~InnerAppAccountManager()
39 {
40     ACCOUNT_LOGI("Destroyed");
41     controlManager_.CloseDataStorage();
42 }
43 
AddAccount(const std::string & name,const std::string & extraInfo,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)44 ErrCode InnerAppAccountManager::AddAccount(const std::string &name, const std::string &extraInfo,
45     const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
46 {
47     AppAccountInfo appAccountInfo(name, bundleName);
48     appAccountInfo.SetAppIndex(appIndex);
49     return controlManager_.AddAccount(name, extraInfo, uid, bundleName, appAccountInfo);
50 }
51 
AddAccountImplicitly(const AuthenticatorSessionRequest & request)52 ErrCode InnerAppAccountManager::AddAccountImplicitly(const AuthenticatorSessionRequest &request)
53 {
54     return sessionManager_.AddAccountImplicitly(request);
55 }
56 
CreateAccount(const std::string & name,const CreateAccountOptions & options,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)57 ErrCode InnerAppAccountManager::CreateAccount(const std::string &name, const CreateAccountOptions &options,
58     const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
59 {
60     AppAccountInfo appAccountInfo(name, bundleName);
61     appAccountInfo.SetAppIndex(appIndex);
62     return controlManager_.CreateAccount(name, options, uid, bundleName, appAccountInfo);
63 }
64 
CreateAccountImplicitly(const AuthenticatorSessionRequest & request)65 ErrCode InnerAppAccountManager::CreateAccountImplicitly(const AuthenticatorSessionRequest &request)
66 {
67     return sessionManager_.CreateAccountImplicitly(request);
68 }
69 
DeleteAccount(const std::string & name,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)70 ErrCode InnerAppAccountManager::DeleteAccount(
71     const std::string &name, const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
72 {
73     AppAccountInfo appAccountInfo(name, bundleName);
74     appAccountInfo.SetAppIndex(appIndex);
75     // After deleting the account, the AuthorizedApp information not exists in the appAccountInfo
76     std::shared_ptr<AppAccountDataStorage> dataStoragePtr =
77         controlManager_.GetDataStorage(uid);
78     auto ret = controlManager_.GetAccountInfoFromDataStorage(appAccountInfo, dataStoragePtr);
79     if (ret != ERR_OK) {
80         ACCOUNT_LOGE("Failed to get account info from data storage, result %{public}d.", ret);
81         return ret;
82     }
83     std::set<std::string> authorizedApps;
84     appAccountInfo.GetAuthorizedApps(authorizedApps);
85     ErrCode result = controlManager_.DeleteAccount(name, uid, bundleName, appAccountInfo);
86     AppAccountInfo appAccountInfoTemp(name, bundleName);
87     appAccountInfoTemp.SetAppIndex(appIndex);
88     if (result == ERR_OK) {
89         appAccountInfoTemp.SetAuthorizedApps(authorizedApps);
90     }
91     if ((result == ERR_OK) && (!subscribeManager_.PublishAccount(appAccountInfoTemp, uid, bundleName))) {
92         ACCOUNT_LOGE("failed to publish account");
93     }
94     return result;
95 }
96 
GetAccountExtraInfo(const std::string & name,std::string & extraInfo,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)97 ErrCode InnerAppAccountManager::GetAccountExtraInfo(const std::string &name, std::string &extraInfo,
98     const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
99 {
100     return controlManager_.GetAccountExtraInfo(name, extraInfo, uid, bundleName, appIndex);
101 }
102 
SetAccountExtraInfo(const std::string & name,const std::string & extraInfo,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)103 ErrCode InnerAppAccountManager::SetAccountExtraInfo(const std::string &name, const std::string &extraInfo,
104     const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
105 {
106     AppAccountInfo appAccountInfo(name, bundleName);
107     appAccountInfo.SetAppIndex(appIndex);
108     ErrCode result = controlManager_.SetAccountExtraInfo(name, extraInfo, uid, bundleName, appAccountInfo);
109     if ((result == ERR_OK) && (!subscribeManager_.PublishAccount(appAccountInfo, uid, bundleName))) {
110         ACCOUNT_LOGE("failed to publish account");
111     }
112     return result;
113 }
114 
EnableAppAccess(const std::string & name,const std::string & authorizedApp,AppAccountCallingInfo & appAccountCallingInfo,const uint32_t apiVersion)115 ErrCode InnerAppAccountManager::EnableAppAccess(const std::string &name, const std::string &authorizedApp,
116     AppAccountCallingInfo &appAccountCallingInfo, const uint32_t apiVersion)
117 {
118     AppAccountInfo appAccountInfo(name, appAccountCallingInfo.bundleName);
119     appAccountInfo.SetAppIndex(appAccountCallingInfo.appIndex);
120     ErrCode result = controlManager_.EnableAppAccess(
121         name, authorizedApp, appAccountCallingInfo, appAccountInfo, apiVersion);
122     if ((result == ERR_OK) && (!subscribeManager_.PublishAccount(
123         appAccountInfo, appAccountCallingInfo.callingUid, appAccountCallingInfo.bundleName))) {
124         ACCOUNT_LOGE("failed to publish account");
125     }
126     return result;
127 }
128 
DisableAppAccess(const std::string & name,const std::string & authorizedApp,AppAccountCallingInfo & appAccountCallingInfo,const uint32_t apiVersion)129 ErrCode InnerAppAccountManager::DisableAppAccess(const std::string &name, const std::string &authorizedApp,
130     AppAccountCallingInfo &appAccountCallingInfo, const uint32_t apiVersion)
131 {
132     AppAccountInfo appAccountInfo(name, appAccountCallingInfo.bundleName);
133     appAccountInfo.SetAppIndex(appAccountCallingInfo.appIndex);
134     ErrCode result = controlManager_.DisableAppAccess(
135         name, authorizedApp, appAccountCallingInfo, appAccountInfo, apiVersion);
136     if (result == ERR_OK) {
137         // After DisableAppAccess, the AuthorizedApp information not exists in the appAccountInfo
138         appAccountInfo.EnableAppAccess(authorizedApp, apiVersion);
139     }
140     if ((result == ERR_OK) && (!subscribeManager_.PublishAccount(
141         appAccountInfo, appAccountCallingInfo.callingUid, appAccountCallingInfo.bundleName))) {
142         ACCOUNT_LOGE("failed to publish account");
143     }
144     return result;
145 }
146 
CheckAppAccess(const std::string & name,const std::string & authorizedApp,bool & isAccessible,const AppAccountCallingInfo & appAccountCallingInfo)147 ErrCode InnerAppAccountManager::CheckAppAccess(const std::string &name, const std::string &authorizedApp,
148     bool &isAccessible, const AppAccountCallingInfo &appAccountCallingInfo)
149 {
150     return controlManager_.CheckAppAccess(name, authorizedApp, isAccessible, appAccountCallingInfo);
151 }
152 
CheckAppAccountSyncEnable(const std::string & name,bool & syncEnable,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)153 ErrCode InnerAppAccountManager::CheckAppAccountSyncEnable(const std::string &name, bool &syncEnable,
154     const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
155 {
156     return controlManager_.CheckAppAccountSyncEnable(name, syncEnable, uid, bundleName, appIndex);
157 }
158 
SetAppAccountSyncEnable(const std::string & name,const bool & syncEnable,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)159 ErrCode InnerAppAccountManager::SetAppAccountSyncEnable(const std::string &name, const bool &syncEnable,
160     const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
161 {
162     AppAccountInfo appAccountInfo(name, bundleName);
163     appAccountInfo.SetAppIndex(appIndex);
164     return controlManager_.SetAppAccountSyncEnable(name, syncEnable, uid, bundleName, appAccountInfo);
165 }
166 
GetAssociatedData(const std::string & name,const std::string & key,std::string & value,const uid_t & uid)167 ErrCode InnerAppAccountManager::GetAssociatedData(const std::string &name, const std::string &key,
168     std::string &value, const uid_t &uid)
169 {
170     return controlManager_.GetAssociatedData(name, key, value, uid);
171 }
172 
SetAssociatedData(const std::string & name,const std::string & key,const std::string & value,const AppAccountCallingInfo & appAccountCallingInfo)173 ErrCode InnerAppAccountManager::SetAssociatedData(const std::string &name, const std::string &key,
174     const std::string &value, const AppAccountCallingInfo &appAccountCallingInfo)
175 {
176     ErrCode result = controlManager_.SetAssociatedData(name, key, value, appAccountCallingInfo);
177     if (result != ERR_OK) {
178         return result;
179     }
180     // Need to query the real appAccountInfo in the database.
181     AppAccountInfo appAccountInfo(name, appAccountCallingInfo.bundleName);
182     appAccountInfo.SetAppIndex(appAccountCallingInfo.appIndex);
183     std::shared_ptr<AppAccountDataStorage> dataStoragePtr =
184         controlManager_.GetDataStorage(appAccountCallingInfo.callingUid);
185     auto ret = controlManager_.GetAccountInfoFromDataStorage(appAccountInfo, dataStoragePtr);
186     if (ret != ERR_OK) {
187         ACCOUNT_LOGE("Failed to get account info from data storage, result %{public}d.", ret);
188         return ret;
189     }
190     if (!subscribeManager_.PublishAccount(appAccountInfo,
191         appAccountCallingInfo.callingUid, appAccountCallingInfo.bundleName)) {
192         ACCOUNT_LOGE("failed to publish account");
193     }
194     return result;
195 }
196 
GetAccountCredential(const std::string & name,const std::string & credentialType,std::string & credential,const AppAccountCallingInfo & appAccountCallingInfo)197 ErrCode InnerAppAccountManager::GetAccountCredential(const std::string &name, const std::string &credentialType,
198     std::string &credential, const AppAccountCallingInfo &appAccountCallingInfo)
199 {
200     return controlManager_.GetAccountCredential(name, credentialType, credential, appAccountCallingInfo);
201 }
202 
SetAccountCredential(const std::string & name,const std::string & credentialType,const std::string & credential,const AppAccountCallingInfo & appAccountCallingInfo)203 ErrCode InnerAppAccountManager::SetAccountCredential(const std::string &name, const std::string &credentialType,
204     const std::string &credential, const AppAccountCallingInfo &appAccountCallingInfo)
205 {
206     ErrCode result = controlManager_.SetAccountCredential(name, credentialType, credential, appAccountCallingInfo);
207     if (result != ERR_OK) {
208         return result;
209     }
210     AppAccountInfo appAccountInfo(name, appAccountCallingInfo.bundleName);
211     appAccountInfo.SetAppIndex(appAccountCallingInfo.appIndex);
212     // Need to query the real appAccountInfo in the database.
213     std::shared_ptr<AppAccountDataStorage> dataStoragePtr =
214         controlManager_.GetDataStorage(appAccountCallingInfo.callingUid);
215     auto ret = controlManager_.GetAccountInfoFromDataStorage(appAccountInfo, dataStoragePtr);
216     if (ret != ERR_OK) {
217         ACCOUNT_LOGE("Failed to get account info from data storage, result %{public}d.", ret);
218         return ret;
219     }
220     if (!subscribeManager_.PublishAccount(appAccountInfo,
221         appAccountCallingInfo.callingUid, appAccountCallingInfo.bundleName)) {
222         ACCOUNT_LOGE("failed to publish account");
223     }
224     return result;
225 }
226 
DeleteAccountCredential(const std::string & name,const std::string & credentialType,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)227 ErrCode InnerAppAccountManager::DeleteAccountCredential(const std::string &name, const std::string &credentialType,
228     const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
229 {
230     AppAccountCallingInfo appAccountCallingInfo;
231     appAccountCallingInfo.callingUid = uid;
232     appAccountCallingInfo.bundleName = bundleName;
233     appAccountCallingInfo.appIndex = appIndex;
234     ErrCode result = controlManager_.DeleteAccountCredential(name, credentialType, appAccountCallingInfo);
235     if (result != ERR_OK) {
236         return result;
237     }
238     AppAccountInfo appAccountInfo(name, bundleName);
239     appAccountInfo.SetAppIndex(appIndex);
240     // Need to query the real appAccountInfo in the database.
241     std::shared_ptr<AppAccountDataStorage> dataStoragePtr =
242         controlManager_.GetDataStorage(appAccountCallingInfo.callingUid);
243     auto ret = controlManager_.GetAccountInfoFromDataStorage(appAccountInfo, dataStoragePtr);
244     if (ret != ERR_OK) {
245         ACCOUNT_LOGE("Failed to get account info from data storage, result %{public}d.", ret);
246         return ret;
247     }
248     if (!subscribeManager_.PublishAccount(appAccountInfo, uid, bundleName)) {
249         ACCOUNT_LOGE("failed to publish account");
250     }
251     return result;
252 }
253 
Authenticate(const AuthenticatorSessionRequest & request)254 ErrCode InnerAppAccountManager::Authenticate(const AuthenticatorSessionRequest &request)
255 {
256     std::string token;
257     ErrCode ret = ERR_OK;
258     bool isApi9 = request.options.GetBoolParam(Constants::API_V9, false);
259     if (isApi9) {
260         ret = controlManager_.GetOAuthToken(request, token, Constants::API_VERSION9);
261     } else {
262         ret = controlManager_.GetOAuthToken(request, token);
263     }
264     if (ret == ERR_OK) {
265         if ((request.callback != nullptr) && (request.callback->AsObject() != nullptr)) {
266             AAFwk::Want result;
267             result.SetParam(Constants::KEY_NAME, request.name);
268             result.SetParam(Constants::KEY_AUTH_TYPE, request.authType);
269             result.SetParam(Constants::KEY_TOKEN, token);
270             request.callback->OnResult(ERR_OK, result);
271         }
272         return ERR_OK;
273     }
274     if (isApi9) {
275         return sessionManager_.Auth(request);
276     }
277     return sessionManager_.Authenticate(request);
278 }
279 
GetOAuthToken(const AuthenticatorSessionRequest & request,std::string & token,const uint32_t apiVersion)280 ErrCode InnerAppAccountManager::GetOAuthToken(
281     const AuthenticatorSessionRequest &request, std::string &token, const uint32_t apiVersion)
282 {
283     return controlManager_.GetOAuthToken(request, token, apiVersion);
284 }
285 
SetOAuthToken(const AuthenticatorSessionRequest & request)286 ErrCode InnerAppAccountManager::SetOAuthToken(const AuthenticatorSessionRequest &request)
287 {
288     ErrCode result = controlManager_.SetOAuthToken(request);
289     if (result != ERR_OK) {
290         return result;
291     }
292     AppAccountInfo appAccountInfo(request.name, request.callerBundleName);
293     appAccountInfo.SetAppIndex(request.appIndex);
294     // Need to query the real appAccountInfo in the database.
295     std::shared_ptr<AppAccountDataStorage> dataStoragePtr =
296         controlManager_.GetDataStorage(request.callerUid);
297     auto ret = controlManager_.GetAccountInfoFromDataStorage(appAccountInfo, dataStoragePtr);
298     if (ret != ERR_OK) {
299         ACCOUNT_LOGE("Failed to get account info from data storage, result %{public}d.", ret);
300         return ret;
301     }
302     if (!subscribeManager_.PublishAccount(appAccountInfo, request.callerUid, request.callerBundleName)) {
303         ACCOUNT_LOGE("failed to publish account");
304     }
305     return ERR_OK;
306 }
307 
DeleteOAuthToken(const AuthenticatorSessionRequest & request,const uint32_t apiVersion)308 ErrCode InnerAppAccountManager::DeleteOAuthToken(const AuthenticatorSessionRequest &request, const uint32_t apiVersion)
309 {
310     return controlManager_.DeleteOAuthToken(request, apiVersion);
311 }
312 
SetOAuthTokenVisibility(const AuthenticatorSessionRequest & request,const uint32_t apiVersion)313 ErrCode InnerAppAccountManager::SetOAuthTokenVisibility(
314     const AuthenticatorSessionRequest &request, const uint32_t apiVersion)
315 {
316     return controlManager_.SetOAuthTokenVisibility(request, apiVersion);
317 }
318 
CheckOAuthTokenVisibility(const AuthenticatorSessionRequest & request,bool & isVisible,const uint32_t apiVersion)319 ErrCode InnerAppAccountManager::CheckOAuthTokenVisibility(
320     const AuthenticatorSessionRequest &request, bool &isVisible, const uint32_t apiVersion)
321 {
322     return controlManager_.CheckOAuthTokenVisibility(request, isVisible, apiVersion);
323 }
324 
GetAuthenticatorInfo(const AuthenticatorSessionRequest & request,AuthenticatorInfo & info)325 ErrCode InnerAppAccountManager::GetAuthenticatorInfo(
326     const AuthenticatorSessionRequest &request, AuthenticatorInfo &info)
327 {
328     return AppAccountAuthenticatorManager::GetAuthenticatorInfo(
329         request.owner, request.callerUid / UID_TRANSFORM_DIVISOR, info);
330 }
331 
GetAllOAuthTokens(const AuthenticatorSessionRequest & request,std::vector<OAuthTokenInfo> & tokenInfos)332 ErrCode InnerAppAccountManager::GetAllOAuthTokens(
333     const AuthenticatorSessionRequest &request, std::vector<OAuthTokenInfo> &tokenInfos)
334 {
335     return controlManager_.GetAllOAuthTokens(request, tokenInfos);
336 }
337 
GetOAuthList(const AuthenticatorSessionRequest & request,std::set<std::string> & oauthList,const uint32_t apiVersion)338 ErrCode InnerAppAccountManager::GetOAuthList(
339     const AuthenticatorSessionRequest &request, std::set<std::string> &oauthList, const uint32_t apiVersion)
340 {
341     return controlManager_.GetOAuthList(request, oauthList, apiVersion);
342 }
343 
GetAuthenticatorCallback(const AuthenticatorSessionRequest & request,sptr<IRemoteObject> & callback)344 ErrCode InnerAppAccountManager::GetAuthenticatorCallback(
345     const AuthenticatorSessionRequest &request, sptr<IRemoteObject> &callback)
346 {
347     callback = nullptr;
348     return sessionManager_.GetAuthenticatorCallback(request, callback);
349 }
350 
GetAllAccounts(const std::string & owner,std::vector<AppAccountInfo> & appAccounts,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)351 ErrCode InnerAppAccountManager::GetAllAccounts(const std::string &owner, std::vector<AppAccountInfo> &appAccounts,
352     const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
353 {
354     return controlManager_.GetAllAccounts(owner, appAccounts, uid, bundleName, appIndex);
355 }
356 
GetAllAccessibleAccounts(std::vector<AppAccountInfo> & appAccounts,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)357 ErrCode InnerAppAccountManager::GetAllAccessibleAccounts(std::vector<AppAccountInfo> &appAccounts,
358     const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
359 {
360     return controlManager_.GetAllAccessibleAccounts(appAccounts, uid, bundleName, appIndex);
361 }
362 
SelectAccountsByOptions(const SelectAccountsOptions & options,const sptr<IAppAccountAuthenticatorCallback> & callback,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)363 ErrCode InnerAppAccountManager::SelectAccountsByOptions(
364     const SelectAccountsOptions &options, const sptr<IAppAccountAuthenticatorCallback> &callback,
365     const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
366 {
367     AuthenticatorSessionRequest request;
368     return controlManager_.SelectAccountsByOptions(options, callback, uid, bundleName, appIndex);
369 }
370 
VerifyCredential(const AuthenticatorSessionRequest & request)371 ErrCode InnerAppAccountManager::VerifyCredential(const AuthenticatorSessionRequest &request)
372 {
373     return sessionManager_.VerifyCredential(request);
374 }
375 
CheckAccountLabels(const AuthenticatorSessionRequest & request)376 ErrCode InnerAppAccountManager::CheckAccountLabels(const AuthenticatorSessionRequest &request)
377 {
378     return sessionManager_.CheckAccountLabels(request);
379 }
380 
SetAuthenticatorProperties(const AuthenticatorSessionRequest & request)381 ErrCode InnerAppAccountManager::SetAuthenticatorProperties(const AuthenticatorSessionRequest &request)
382 {
383     return sessionManager_.SetAuthenticatorProperties(request);
384 }
385 
SubscribeAppAccount(const AppAccountSubscribeInfo & subscribeInfo,const sptr<IRemoteObject> & eventListener,const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)386 ErrCode InnerAppAccountManager::SubscribeAppAccount(const AppAccountSubscribeInfo &subscribeInfo,
387     const sptr<IRemoteObject> &eventListener, const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
388 {
389     auto subscribeInfoPtr = std::make_shared<AppAccountSubscribeInfo>(subscribeInfo);
390     return subscribeManager_.SubscribeAppAccount(subscribeInfoPtr, eventListener, uid, bundleName, appIndex);
391 }
392 
UnsubscribeAppAccount(const sptr<IRemoteObject> & eventListener)393 ErrCode InnerAppAccountManager::UnsubscribeAppAccount(const sptr<IRemoteObject> &eventListener)
394 {
395     return subscribeManager_.UnsubscribeAppAccount(eventListener);
396 }
397 
OnPackageRemoved(const uid_t & uid,const std::string & bundleName,const uint32_t & appIndex)398 ErrCode InnerAppAccountManager::OnPackageRemoved(
399     const uid_t &uid, const std::string &bundleName, const uint32_t &appIndex)
400 {
401     return controlManager_.OnPackageRemoved(uid, bundleName, appIndex);
402 }
403 
OnUserRemoved(int32_t userId)404 ErrCode InnerAppAccountManager::OnUserRemoved(int32_t userId)
405 {
406     return controlManager_.OnUserRemoved(userId);
407 }
408 }  // namespace AccountSA
409 }  // namespace OHOS
410