淘先锋技术网

首页 1 2 3 4 5 6 7

1 account组件框架

在标准系统上,系统帐号组件主要提供分布式帐号登录状态管理能力,支持在端侧对接厂商云帐号应用,提供云帐号登录状态查询和更新的管理能力。

img

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));
}

惊呆了,这里居然是调用OhosAccountManagerGetAccountInfo。好吧,那就看看吧。

//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_进行对比,如果状态不一样即切换到新状态。