1 account组件框架
在标准系统上,系统帐号组件主要提供分布式帐号登录状态管理能力,支持在端侧对接厂商云帐号应用,提供云帐号登录状态查询和更新的管理能力。
2 目录结构
/base/account/os_account
├── common # 公共基础模块
│ ├── account_error # 错误码定义
│ ├── log # 日志打印代码
│ ├── perf_stat # 性能统计
│ └── test # 公共模块测试代码
├── interfaces # 对外接口存放目录
│ └── innerkits # 对内部组件暴露的头文件存放目录
├── kits # 系统帐号组件开发框架
├── sa_profile # 帐号SA配置文件定义目录
├── services # 系统帐号组件服务代码
│ └── accountmgr # 帐号管理服务目录
└── test # 系统帐号组件测试代码
└── resource # 系统帐号组件测试资源
3 接口
方法 | 描述 |
---|---|
getDistributedAccountAbility | 获取分布式帐号信息 |
queryOsAccountDistributedInfo | 查询分布式帐号信息 |
updateOsAccountDistributedInfo | 更新分布式帐号信息 |
4 account组件启动
4.1 rc启动服务
#base\account\os_account\services\accountmgr\accountmgr.rc
on post-fs-data
start accountmgr
service accountmgr /system/bin/sa_main /system/profile/accountmgr.xml
class z_core
user system
group system shell
seclabel u:r:accountmgr:s0
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks /dev/blkio/foreground/tasks
account组件是在post-fs-data
启动的,再来看配置文件
//base\account\os_account\sa_profile\200.xml
<info>
<process>accountmgr</process>
<systemability> <!-- Declare a system ability and its profile -->
<name>200</name> <!-- Declare the name of system ability -->
<libpath>libaccountmgr.z.so</libpath>
<run-on-create>true</run-on-create>
<distributed>false</distributed>
<dump-level>1</dump-level> <!-- Declare the dump level. 1-high; 2-media; 3-low -->
</systemability>
</info>
那么accountmgr是怎么启动的呢
4.2 AccountMgrService启动
//base\account\os_account\services\accountmgr\src\account_mgr_service.cpp
void AccountMgrService::OnStart()
{
if (state_ == ServiceRunningState::STATE_RUNNING) {
ACCOUNT_LOGI("AccountMgrService has already started.");
return;
}
PerfStat::GetInstance().SetInstanceStartTime(GetTickCount());
ACCOUNT_LOGI("start is triggered");
if (!Init()) {
ACCOUNT_LOGE("failed to init AccountMgrService");
return;
}
state_ = ServiceRunningState::STATE_RUNNING;
ACCOUNT_LOGI("AccountMgrService::OnStart start service success.");
}
第一次启动,这里是调用Init。
//base\account\os_account\services\accountmgr\src\account_mgr_service.cpp
bool AccountMgrService::Init()
{
if (state_ == ServiceRunningState::STATE_RUNNING) {
ACCOUNT_LOGW("Service is already running!");
return false;
}
if (!OHOS::FileExists(DEVICE_OWNER_DIR)) {
ACCOUNT_LOGI("Device owner dir not exist, create!");
if (!OHOS::ForceCreateDirectory(DEVICE_OWNER_DIR)) {
ACCOUNT_LOGW("Create device owner dir failure!");
}
}
bool ret = false;
if (!registerToService_) {
ret = Publish(&DelayedRefSingleton<AccountMgrService>::GetInstance());
if (!ret) {
HiviewDFX::HiSysEvent::Write(HiviewDFX::HiSysEvent::Domain::ACCOUNT, "AccountServiceStartFailed",
HiviewDFX::HiSysEvent::EventType::FAULT, "ERROR_TYPE", ERR_ACCOUNT_MGR_ADD_TO_SA_ERROR);
ACCOUNT_LOGE("AccountMgrService::Init Publish failed!");
return false;
}
registerToService_ = true;
}
PerfStat::GetInstance().SetInstanceInitTime(GetTickCount());
ohosAccountMgr_ = std::make_shared<OhosAccountManager>();
ret = ohosAccountMgr_->OnInitialize();
if (!ret) {
ACCOUNT_LOGE("Ohos account manager initialize failed");
HiviewDFX::HiSysEvent::Write(HiviewDFX::HiSysEvent::Domain::ACCOUNT, "AccountServiceStartFailed",
HiviewDFX::HiSysEvent::EventType::FAULT, "ERROR_TYPE", ret);
return ret;
}
dumpHelper_ = std::make_unique<AccountDumpHelper>(ohosAccountMgr_);
IAccountContext::SetInstance(this);
ACCOUNT_LOGI("init end success");
return true;
}
Init接口首先检查DEVICE_OWNER_DIR 是否存在,这个文件的路径是/data/system/users/0/
,如果不存在就创建。然后就是通过Publish来注册服务。然后调用OhosAccountManager的OnInitialize()方法。
4.3 OhosAccountManager初始化
//base\account\os_account\services\accountmgr\src\ohos_account_manager.cpp
bool OhosAccountManager::OnInitialize()
{
accountState_ = std::make_unique<AccountStateMachine>();
BuildEventsMapper();
std::int32_t userId = GetUserId();
std::string filePath;
filePath.append(ACCOUNT_CFG_DIR_ROOT_PATH).append(std::to_string(userId)).append(ACCOUNT_CFG_FILE_NAME);
dataDealer_ = std::make_unique<OhosAccountDataDeal>(filePath);
std::int32_t tryTimes = 0;
while (tryTimes < MAX_RETRY_TIMES) {
tryTimes++;
ErrCode errCode = dataDealer_->Init();
if (errCode == ERR_OK) {
break;
}
// when json file corrupted, have it another try
if ((tryTimes == MAX_RETRY_TIMES) || (errCode != ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION)) {
ACCOUNT_LOGE("parse json file failed: %{public}d, tryTime: %{public}d", errCode, tryTimes);
eventMap_.clear();
eventFuncMap_.clear();
return false;
}
}
// get account info from config file
dataDealer_->AccountInfoFromJson(currentAccount_);
accountState_->SetAccountState(currentAccount_.ohosAccountStatus_);
return true;
}
OhosAccountManager::OnInitialize
首先调用BuildEventsMapper进行事件监听。
//base\account\os_account\services\accountmgr\src\ohos_account_manager.cpp
void OhosAccountManager::BuildEventsMapper()
{
eventMap_.insert(std::pair<std::string, ACCOUNT_INNER_EVENT_TYPE>(OHOS_ACCOUNT_EVENT_LOGIN,
ACCOUNT_BIND_SUCCESS_EVT));
eventMap_.insert(std::pair<std::string, ACCOUNT_INNER_EVENT_TYPE>(OHOS_ACCOUNT_EVENT_LOGOUT,
ACCOUNT_MANUAL_UNBOUND_EVT));
eventMap_.insert(std::pair<std::string, ACCOUNT_INNER_EVENT_TYPE>(OHOS_ACCOUNT_EVENT_TOKEN_INVALID,
ACCOUNT_TOKEN_EXPIRED_EVT));
eventMap_.insert(std::pair<std::string, ACCOUNT_INNER_EVENT_TYPE>(OHOS_ACCOUNT_EVENT_LOGOFF,
ACCOUNT_MANUAL_LOGOFF_EVT));
eventFuncMap_.insert(std::make_pair(OHOS_ACCOUNT_EVENT_LOGIN, &OhosAccountManager::LoginOhosAccount));
eventFuncMap_.insert(std::make_pair(OHOS_ACCOUNT_EVENT_LOGOUT, &OhosAccountManager::LogoutOhosAccount));
eventFuncMap_.insert(std::make_pair(OHOS_ACCOUNT_EVENT_LOGOFF, &OhosAccountManager::LogoffOhosAccount));
eventFuncMap_.insert(std::make_pair(OHOS_ACCOUNT_EVENT_TOKEN_INVALID,
&OhosAccountManager::HandleOhosAccountTokenInvalidEvent));
}
事件主要由4个:
//base\account\os_account\interfaces\innerkits\include\account_info.h
// event string
const std::string OHOS_ACCOUNT_EVENT_LOGIN = "Ohos.account.event.LOGIN";
const std::string OHOS_ACCOUNT_EVENT_LOGOUT = "Ohos.account.event.LOGOUT";
const std::string OHOS_ACCOUNT_EVENT_TOKEN_INVALID = "Ohos.account.event.TOKEN_INVALID";
const std::string OHOS_ACCOUNT_EVENT_LOGOFF = "Ohos.account.event.LOGOFF";
然后调用ohos_account_data_deal的init方法
4.4 ohos_account_data_deal初始化化
//base\account\os_account\services\accountmgr\src\ohos_account_data_deal.cpp
ErrCode OhosAccountDataDeal::Init()
{
if (!FileExists(configFile_)) {
ACCOUNT_LOGI("file %{public}s not exist, create!", configFile_.c_str());
BuildJsonFileFromScratch();
}
std::ifstream fin(configFile_);
if (!fin) {
ACCOUNT_LOGE("Failed to open file %{public}s", configFile_.c_str());
return ERR_ACCOUNT_DATADEAL_INPUT_FILE_ERROR;
}
// NOT-allow exceptions when parse json file
nlohmann::json jsonData = json::parse(fin, nullptr, false);
if (!jsonData.is_structured()) {
ACCOUNT_LOGE("Invalid json file, remove");
fin.close();
if (RemoveFile(configFile_)) {
ACCOUNT_LOGE("Remove invalid json file failed");
}
return ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION;
}
// jsonData_ keeps well-structured json key-values
jsonData_ = jsonData;
initOk_ = true;
fin.close();
return ERR_OK;
}
读取用户账号配置文件/data/system/users/account.json
到jsonData_中进行保存。然后调用AccountInfoFromJson将账号信息保存到currentAccount_。
因此,可以看到,AccountMgrService在启动的时候主要是做一些初始化的工作。
5 接口调用流程
这里以queryOsAccountDistributedInfo为例,来分析调用流程。
//base\account\os_account\kits\js\impl\napi\distributedaccount\napi_distributed_account.cpp
napi_value NapiDistributedAccount::Init(napi_env env, napi_value exports)
{
ACCOUNT_LOGI("enter");
napi_property_descriptor descriptor[] = {
DECLARE_NAPI_FUNCTION("getDistributedAccountAbility", GetDistributedAccountAbility),
};
napi_define_properties(env, exports, sizeof(descriptor) / sizeof(napi_property_descriptor), descriptor);
napi_property_descriptor properties[] = {
DECLARE_NAPI_FUNCTION("queryOsAccountDistributedInfo", QueryOhosAccountInfo),
DECLARE_NAPI_FUNCTION("updateOsAccountDistributedInfo", UpdateOsAccountDistributedInfo),
};
napi_value cons = nullptr;
napi_define_class(env, DISTRIBUTED_ACCOUNT_CLASS_NAME.c_str(), DISTRIBUTED_ACCOUNT_CLASS_NAME.size(),
JsConstructor, nullptr, sizeof(properties) / sizeof(napi_property_descriptor), properties, &cons);
napi_create_reference(env, cons, 1, &constructorRef_);
napi_set_named_property(env, exports, DISTRIBUTED_ACCOUNT_CLASS_NAME.c_str(), cons);
return exports;
}
queryOsAccountDistributedInfo接口实际调用的是QueryOhosAccountInfo:
//base\account\os_account\kits\js\impl\napi\distributedaccount\napi_distributed_account.cpp
napi_value NapiDistributedAccount::QueryOhosAccountInfo(napi_env env, napi_callback_info cbInfo)
{
......
napi_create_async_work(
env, nullptr, resource,
[](napi_env env, void *data) {
DistributedAccountAsyncContext *asyncContext = (DistributedAccountAsyncContext*)data;
std::pair<bool, OhosAccountInfo> accountInfo = OhosAccountKits::GetInstance().QueryOhosAccountInfo();
......
return result;
}
原来实际调用的是OhosAccountKits::GetInstance().QueryOhosAccountInfo()
//base\account\os_account\interfaces\innerkits\accountmgr\src\ohos_account_kits_impl.cpp
std::pair<bool, OhosAccountInfo> OhosAccountKitsImpl::QueryOhosAccountInfo()
{
auto accountProxy = GetService();
if (accountProxy == nullptr) {
ACCOUNT_LOGE("Get proxy failed");
return std::make_pair(false, OhosAccountInfo());
}
return accountProxy->QueryOhosAccountInfo();
}
QueryOhosAccountInfo实际上是通过Proxy来获取AccountInfo
//base\account\os_account\interfaces\innerkits\accountmgr\src\account_proxy.cpp
std::pair<bool, OhosAccountInfo> AccountProxy::QueryOhosAccountInfo(void)
{
ACCOUNT_LOGI("QueryOhosAccountInfo enter");
MessageParcel data;
if (!data.WriteInterfaceToken(AccountProxy::GetDescriptor())) {
ACCOUNT_LOGE("Write descriptor failed");
return std::make_pair(false, OhosAccountInfo());
}
MessageParcel reply;
MessageOption option;
auto ret = Remote()->SendRequest(QUERY_OHOS_ACCOUNT_INFO, data, reply, option);
if (ret != ERR_NONE) {
ACCOUNT_LOGE("SendRequest failed %d", ret);
return std::make_pair(false, OhosAccountInfo());
}
std::u16string name = reply.ReadString16();
std::u16string uid = reply.ReadString16();
std::int32_t status = reply.ReadInt32();
ACCOUNT_LOGI("QueryOhosAccountInfo exit");
return std::make_pair(true, OhosAccountInfo(Str16ToStr8(name), Str16ToStr8(uid), status));
}
我们来看看AccountProxy::QueryOhosAccountInfo
是如何通过QUERY_OHOS_ACCOUNT_INFO来和服务端通信的。
//base\account\os_account\services\accountmgr\src\account_stub.cpp
std::int32_t AccountStub::OnRemoteRequest(std::uint32_t code, MessageParcel &data,
MessageParcel &reply, MessageOption &option)
{
ACCOUNT_LOGI("Received stub message: %{public}d", code);
if (!IsServiceStarted()) {
ACCOUNT_LOGE("account mgr not ready");
return ERR_ACCOUNT_ZIDL_MGR_NOT_READY_ERROR;
}
if (!CheckCallerForTrustList()) {
const std::u16string descriptor = AccountStub::GetDescriptor();
const std::u16string remoteDescriptor = data.ReadInterfaceToken();
if (descriptor != remoteDescriptor) {
ACCOUNT_LOGE("Check remote descriptor failed");
return ERR_ACCOUNT_ZIDL_ACCOUNT_STUB_ERROR;
}
}
const auto &itFunc = stubFuncMap_.find(code);
if (itFunc != stubFuncMap_.end()) {
return (this->*(itFunc->second))(data, reply);
}
ACCOUNT_LOGW("remote request unhandled: %{public}d", code);
return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
}
原来是从stubFuncMap_从来匹配请求码,然后获取stubFuncMap_的第二项来处理请求。那我们来看看stubFuncMap_长啥样。
//base\account\os_account\services\accountmgr\src\account_stub.cpp
const std::map<std::uint32_t, AccountStubFunc> AccountStub::stubFuncMap_ {
std::make_pair(UPDATE_OHOS_ACCOUNT_INFO, &AccountStub::CmdUpdateOhosAccountInfo),
std::make_pair(QUERY_OHOS_ACCOUNT_INFO, &AccountStub::CmdQueryOhosAccountInfo),
std::make_pair(QUERY_OHOS_ACCOUNT_QUIT_TIPS, &AccountStub::CmdQueryOhosQuitTips),
std::make_pair(QUERY_DEVICE_ACCOUNT_ID, &AccountStub::CmdQueryDeviceAccountId),
std::make_pair(QUERY_DEVICE_ACCOUNT_ID_FROM_UID, &AccountStub::CmdQueryDeviceAccountIdFromUid),
};
很容易看出,QUERY_OHOS_ACCOUNT_INFO对应的是AccountStub::CmdQueryOhosAccountInfo
//base\account\os_account\services\accountmgr\src\account_stub.cpp
std::int32_t AccountStub::CmdQueryOhosAccountInfo(MessageParcel &data, MessageParcel &reply)
{
if (!IsRootOrSystemAccount() && !HasAccountRequestPermission(PERMISSION_MANAGE_USERS)) {
ACCOUNT_LOGE("Check permission failed");
return ERR_ACCOUNT_ZIDL_CHECK_PERMISSION_ERROR;
}
std::pair<bool, OhosAccountInfo> info = QueryOhosAccountInfo();
if (!info.first) {
ACCOUNT_LOGE("Query ohos account info failed");
return ERR_ACCOUNT_ZIDL_ACCOUNT_STUB_ERROR;
}
std::string name = info.second.name_;
std::string id = info.second.uid_;
if (!reply.WriteString16(Str8ToStr16(name))) {
ACCOUNT_LOGE("Write name data failed");
return ERR_ACCOUNT_ZIDL_WRITE_NAME_ERROR;
}
if (!reply.WriteString16(Str8ToStr16(id))) {
ACCOUNT_LOGE("Write id data failed");
return ERR_ACCOUNT_ZIDL_WRITE_UID_ERROR;
}
if (!reply.WriteInt32(info.second.status_)) {
ACCOUNT_LOGE("Write status data failed");
return ERR_ACCOUNT_ZIDL_WRITE_ACCOUNT_STATUS_ERROR;
}
return ERR_OK;
}
CmdQueryOhosAccountInfo
中首先检查调用的进程是不是root或者system,从这可以看出,Account的相关接口只有系统用户才能使用。接着检查是否有PERMISSION_MANAGE_USERS权限。
然后获取AccountInfo的其实是QueryOhosAccountInfo,它的实现是在account_mgr_service里面。看到这里感觉马上就能看到庐山真面目了,赶快看看account_mgr_service怎么处理的。
//base\account\os_account\services\accountmgr\src\account_mgr_service.cpp
std::pair<bool, OhosAccountInfo> AccountMgrService::QueryOhosAccountInfo(void)
{
AccountInfo accountInfo = ohosAccountMgr_->GetAccountInfo();
if (accountInfo.ohosAccountUid_.empty()) {
ACCOUNT_LOGE("invalid id");
accountInfo.clear();
}
std::string name = accountInfo.ohosAccountName_;
std::string id = accountInfo.ohosAccountUid_;
std::int32_t status = accountInfo.ohosAccountStatus_;
return std::make_pair(true, OhosAccountInfo(name, id, status));
}
惊呆了,这里居然是调用OhosAccountManager
的GetAccountInfo
。好吧,那就看看吧。
//base\account\os_account\services\accountmgr\src\ohos_account_manager.cpp
AccountInfo OhosAccountManager::GetAccountInfo()
{
std::lock_guard<std::mutex> mutexLock(mgrMutex_);
return currentAccount_;
}
AccountInfo currentAccount_;
这里只是返回currentAccount_变量,它是一个AccountInfo。
那么currentAccount_在哪赋值的呢?
//base\account\os_account\services\accountmgr\src\ohos_account_manager.cpp
bool OhosAccountManager::OnInitialize()
{
accountState_ = std::make_unique<AccountStateMachine>();
BuildEventsMapper();
std::int32_t userId = GetUserId();
std::string filePath;
filePath.append(ACCOUNT_CFG_DIR_ROOT_PATH).append(std::to_string(userId)).append(ACCOUNT_CFG_FILE_NAME);
dataDealer_ = std::make_unique<OhosAccountDataDeal>(filePath);
std::int32_t tryTimes = 0;
while (tryTimes < MAX_RETRY_TIMES) {
tryTimes++;
ErrCode errCode = dataDealer_->Init();
if (errCode == ERR_OK) {
break;
}
// when json file corrupted, have it another try
if ((tryTimes == MAX_RETRY_TIMES) || (errCode != ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION)) {
ACCOUNT_LOGE("parse json file failed: %{public}d, tryTime: %{public}d", errCode, tryTimes);
eventMap_.clear();
eventFuncMap_.clear();
return false;
}
}
// get account info from config file
dataDealer_->AccountInfoFromJson(currentAccount_);
accountState_->SetAccountState(currentAccount_.ohosAccountStatus_);
return true;
}
在Account组件初始化的时候就已经赋值了,来看看dataDealer_->AccountInfoFromJson(currentAccount_);
是怎么做的。
//base\account\os_account\services\accountmgr\src\ohos_account_data_deal.cpp
ErrCode OhosAccountDataDeal::AccountInfoFromJson(AccountInfo &accountInfo)
{
if (!initOk_) {
return ERR_ACCOUNT_DATADEAL_NOT_READY;
}
const auto &jsonObjectEnd = jsonData_.end();
if (jsonData_.find(DATADEAL_JSON_KEY_ACCOUNT_NAME) != jsonObjectEnd) {
accountInfo.ohosAccountName_ = jsonData_.at(DATADEAL_JSON_KEY_ACCOUNT_NAME).get<std::string>();
}
if (jsonData_.find(DATADEAL_JSON_KEY_OPENID) != jsonObjectEnd) {
accountInfo.ohosAccountUid_ = jsonData_.at(DATADEAL_JSON_KEY_OPENID).get<std::string>();
}
if (jsonData_.find(DATADEAL_JSON_KEY_UID) != jsonObjectEnd) {
accountInfo.userId_ = jsonData_.at(DATADEAL_JSON_KEY_UID).get<std::int32_t>();
}
if (jsonData_.find(DATADEAL_JSON_KEY_BIND_TIME) != jsonObjectEnd) {
accountInfo.bindTime_ = jsonData_.at(DATADEAL_JSON_KEY_BIND_TIME).get<std::time_t>();
}
ACCOUNT_LOGI("AccountInfo, bindTime: %{public}ld", accountInfo.bindTime_);
if (jsonData_.find(DATADEAL_JSON_KEY_STATUS) != jsonObjectEnd) {
accountInfo.ohosAccountStatus_ = jsonData_.at(DATADEAL_JSON_KEY_STATUS).get<std::int32_t>();
}
ACCOUNT_LOGI("AccountInfo, ohos account status: %{public}d", accountInfo.ohosAccountStatus_);
return ERR_OK;
}
这里只是解析jsonData_中的数据,然后赋值给accountInfo。jsonData_看名字是一个json数据串,看看它是怎么来的。
//base\account\os_account\services\accountmgr\src\ohos_account_data_deal.cpp
ErrCode OhosAccountDataDeal::Init()
{
if (!FileExists(configFile_)) {
ACCOUNT_LOGI("file %{public}s not exist, create!", configFile_.c_str());
BuildJsonFileFromScratch();
}
std::ifstream fin(configFile_);
if (!fin) {
ACCOUNT_LOGE("Failed to open file %{public}s", configFile_.c_str());
return ERR_ACCOUNT_DATADEAL_INPUT_FILE_ERROR;
}
// NOT-allow exceptions when parse json file
nlohmann::json jsonData = json::parse(fin, nullptr, false);
if (!jsonData.is_structured()) {
ACCOUNT_LOGE("Invalid json file, remove");
fin.close();
if (RemoveFile(configFile_)) {
ACCOUNT_LOGE("Remove invalid json file failed");
}
return ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION;
}
// jsonData_ keeps well-structured json key-values
jsonData_ = jsonData;
initOk_ = true;
fin.close();
return ERR_OK;
}
原来如此,就是从一个配置文件configFile_中读取的用户信息。那么这个配置文件是存在哪里呢?
其实在前面的 OhosAccountManager::OnInitialize()
已经给出了:
//base\account\os_account\services\accountmgr\src\ohos_account_manager.cpp
bool OhosAccountManager::OnInitialize()
{
std::string filePath;
filePath.append(ACCOUNT_CFG_DIR_ROOT_PATH).append(std::to_string(userId)).
append(ACCOUNT_CFG_FILE_NAME);
dataDealer_ = std::make_unique<OhosAccountDataDeal>(filePath);
......
}
//base\account\os_account\services\accountmgr\include\ohos_account_manager.h
const std::string ACCOUNT_CFG_DIR_ROOT_PATH = "/data/system/users/";
const std::string ACCOUNT_CFG_FILE_NAME = "/account.json";
这样既清楚了。
6 账号登入登出
再来看一下账号登录、登出、注销及Token失效等的处理。
//base\account\os_account\services\accountmgr\src\ohos_account_manager.cpp
bool OhosAccountManager::LoginOhosAccount(const std::string &name, const std::string &uid, const std::string &eventStr)
{
std::lock_guard<std::mutex> mutexLock(mgrMutex_);
bool ret = HandleEvent(eventStr); // update account status
if (!ret) {
ACCOUNT_LOGE("LoginOhosAccount: HandleEvent %{public}s failed", eventStr.c_str());
return false;
}
AccountInfo accountInfo(name, uid, currentAccount_.ohosAccountStatus_);
accountInfo.bindTime_ = std::time(nullptr);
accountInfo.userId_ = GetUserId();
ret = SetAccount(accountInfo); // set account info
if (!ret) {
ACCOUNT_LOGE("LoginOhosAccount: SetAccount failed");
return false;
}
ACCOUNT_LOGI("LoginOhosAccount success");
return true;
}
/**
* logout ohos (for distributed network) account.
*
* @param name ohos account name
* @param uid ohos account uid
* @param eventStr ohos account state change event
* @return true if the processing was completed, otherwise false
*/
bool OhosAccountManager::LogoutOhosAccount(const std::string &name, const std::string &uid, const std::string &eventStr)
{
std::lock_guard<std::mutex> mutexLock(mgrMutex_);
bool ret = HandleEvent(eventStr); // update account status
if (!ret) {
ACCOUNT_LOGE("LogoutOhosAccount: HandleEvent %{public}s failed", eventStr.c_str());
return false;
}
ret = ClearAccount(); // clear account info with ACCOUNT_STATE_LOGOUT
if (!ret) {
ACCOUNT_LOGE("LogoutOhosAccount: ClearAccount failed");
return false;
}
ACCOUNT_LOGI("LogoutOhosAccount success");
return true;
}
/**
* logoff ohos (for distributed network) account.
*
* @param name ohos account name
* @param uid ohos account uid
* @param eventStr ohos account state change event
* @return true if the processing was completed, otherwise false
*/
bool OhosAccountManager::LogoffOhosAccount(const std::string &name, const std::string &uid, const std::string &eventStr)
{
std::lock_guard<std::mutex> mutexLock(mgrMutex_);
bool ret = HandleEvent(eventStr); // update account status
if (!ret) {
ACCOUNT_LOGE("LogoffOhosAccount: HandleEvent %{public}s failed", eventStr.c_str());
return false;
}
ret = ClearAccount(ACCOUNT_STATE_LOGOFF); // clear account info with ACCOUNT_STATE_LOGOFF
if (!ret) {
ACCOUNT_LOGE("LogoffOhosAccount: ClearAccount failed");
return false;
}
ACCOUNT_LOGI("LogoffOhosAccount success");
return true;
}
bool OhosAccountManager::HandleOhosAccountTokenInvalidEvent(const std::string &name,
const std::string &uid, const std::string &eventStr)
{
std::lock_guard<std::mutex> mutexLock(mgrMutex_);
bool ret = HandleEvent(eventStr); // update account status
if (!ret) {
ACCOUNT_LOGE("HandleOhosAccountTokenInvalidEvent: HandleEvent %{public}s failed", eventStr.c_str());
return false;
}
AccountInfo accountInfo(name, uid, currentAccount_.ohosAccountStatus_);
accountInfo.userId_ = GetUserId();
ret = SetAccount(accountInfo);
if (!ret) {
// moving on even if failed to update account info
ACCOUNT_LOGW("Handle TokenInvalid event: SetAccount failed");
}
ACCOUNT_LOGI("HandleOhosAccountTokenInvalidEvent success");
return true;
}
从上面可以看出,登录、登出、注销及Token失效操作步骤基本一致,首先对收到的事件进行处理,然后将账号信息更新到缓存和配置文件中。
因此,这里我们只需要看看HandleEvent做了什么处理。
//base\account\os_account\services\accountmgr\src\ohos_account_manager.cpp
bool OhosAccountManager::HandleEvent(const std::string &eventStr)
{
auto iter = eventMap_.find(eventStr);
if (iter == eventMap_.end()) {
ACCOUNT_LOGE("invalid event: %{public}s", eventStr.c_str());
return false;
}
int event = iter->second;
bool ret = accountState_->StateChangeProcess(event);
if (!ret) {
ACCOUNT_LOGE("Handle event %{public}d failed", event);
return false;
}
std::int32_t newState = accountState_->GetAccountState();
if (newState != currentAccount_.ohosAccountStatus_) {
HiviewDFX::HiSysEvent::Write(HiviewDFX::HiSysEvent::Domain::ACCOUNT, "AccountServiceStateMachineEvent",
HiviewDFX::HiSysEvent::EventType::FAULT, "DEVICE_MODE", currentAccount_.userId_,
"OPERATION_TYPE", event, "OLD_STATE", currentAccount_.ohosAccountStatus_, "NEW_STATE", newState);
currentAccount_.ohosAccountStatus_ = newState;
}
return true;
}
首先根据eventStr找到对应的事件类型,然后将事件更新到账号状态机。
//base\account\os_account\services\accountmgr\src\account_state_machine.cpp
bool AccountStateMachine::StateChangeProcess(int evt)
{
// for performance record
std::string stateRecordStr;
int64_t processTicks = GetTickCount();
stateRecordStr.append("state from[").append(std::to_string(currentState_)).append("] to [");
// get all the current state event action
auto stateIter = stateMachineMap_.find(currentState_);
if (stateIter == stateMachineMap_.end()) {
ACCOUNT_LOGE("current state %d is not in state machine map.", currentState_);
return false;
}
// get the current event action
auto eventIter = stateIter->second.find(evt);
if (eventIter == stateIter->second.end()) {
ACCOUNT_LOGE("event %d is not in state machine map.", evt);
return false;
}
// maybe action is null
if (eventIter->second == nullptr) {
ACCOUNT_LOGI("event %d has no action.", evt);
return true;
}
int nextState = eventIter->second->GetNextState();
if (currentState_ != nextState) {
ACCOUNT_LOGI("account state change, (oldstate, newstate) = (%d, %d)", currentState_, nextState);
currentState_ = nextState;
}
// Record state change performance
processTicks = GetTickCount() - processTicks;
stateRecordStr.append(std::to_string(nextState)).append("], event[").append(std::to_string(evt)).append("] Cost");
PerfStat::GetInstance().SetAccountStateChangeTime(stateRecordStr, processTicks);
return true;
}
可以看到,在状态机里面只是简单完成状态的切换。
n false;
}
// maybe action is null
if (eventIter->second == nullptr) {
ACCOUNT_LOGI("event %d has no action.", evt);
return true;
}
int nextState = eventIter->second->GetNextState();
if (currentState_ != nextState) {
ACCOUNT_LOGI("account state change, (oldstate, newstate) = (%d, %d)", currentState_, nextState);
currentState_ = nextState;
}
// Record state change performance
processTicks = GetTickCount() - processTicks;
stateRecordStr.append(std::to_string(nextState)).append("], event[").append(std::to_string(evt)).append("] Cost");
PerfStat::GetInstance().SetAccountStateChangeTime(stateRecordStr, processTicks);
return true;
}
可以看到,在状态机里面只是简单完成状态的切换。
然后HandleEvent里面在状态机切换成功后,再从状态机中取出新状态,然后和OhosAccountManager的当前状态currentAccount_进行对比,如果状态不一样即切换到新状态。