b0c698df创建于 1月16日历史提交
/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "dslm_service.h"

#include <dlfcn.h>
#include <mutex>
#include <thread>

#include "iremote_object.h"
#include "singleton.h"
#include "utils_log.h"
#include "string_ex.h"

#include "device_security_defines.h"
#include "dslm_device_list.h"
#include "dslm_hidumper.h"
#include "dslm_ipc_process.h"
#include "dslm_rpc_process.h"

constexpr uint32_t UNLOAD_TIMEOUT = 10000;

namespace OHOS {
namespace Security {
namespace DeviceSecurityLevel {
REGISTER_SYSTEM_ABILITY_BY_ID(DslmService, DEVICE_SECURITY_LEVEL_MANAGER_SA_ID, true);

DslmService::DslmService(int32_t saId, bool runOnCreate) : SystemAbility(saId, runOnCreate), IRemoteStub(true)
{
    SECURITY_LOG_INFO("object initialization");
    ProcessLoadPlugin();
}

static void TimerProcessUnloadSystemAbility(const void *context)
{
    (void)context;

    if (!JudgeListDeviceType()) {
        return;
    }

    auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    if (samgrProxy == nullptr) {
        SECURITY_LOG_ERROR("get samgr failed");
        return;
    }

    int32_t ret = samgrProxy->UnloadSystemAbility(DEVICE_SECURITY_LEVEL_MANAGER_SA_ID);
    if (ret != ERR_OK) {
        SECURITY_LOG_ERROR("unload system ability failed");
        return;
    }
    SECURITY_LOG_INFO("unload system ability succeed");
}

static void SetSystemAbilityUnloadSchedule(TimerHandle &handle)
{
    if (!JudgeListDeviceType()) {
        return;
    }
    static std::mutex mutex;
    std::lock_guard<std::mutex> lock(mutex);

    if (handle != 0) {
        DslmUtilsStopTimerTask(handle);
    }

    handle = DslmUtilsStartOnceTimerTask(UNLOAD_TIMEOUT, TimerProcessUnloadSystemAbility, nullptr);
}

void DslmService::OnStart()
{
    SECURITY_LOG_INFO("start");
    std::thread thread([this]() {
        if (InitService() == SUCCESS) {
            SECURITY_LOG_INFO("init service success");
        }
        if (!Publish(this)) {
            SECURITY_LOG_ERROR("publish service failed");
        }
        SetSystemAbilityUnloadSchedule(unloadTimerHandle_);
    });
    thread.detach();
}

void DslmService::OnStop()
{
    UnInitService();
    ProcessUnloadPlugin();
    SECURITY_LOG_INFO("stop service");
}

int32_t DslmService::Dump(int fd, const std::vector<std::u16string> &args)
{
    dprintf(fd, "Dslm Dump:\n");
    if (args.size() == 0) {
        dprintf(fd, "please use hidumper -s said -a -h command help\n");
        return 0;
    }
    std::string arg0 = Str16ToStr8(args.at(0));
    if (arg0.compare("-h") == 0) {
        dprintf(fd, "Usage:\n");
        dprintf(fd, "       -h: command help\n");
        dprintf(fd, "       -l: dump all device\n");
    } else if (arg0.compare("-l") == 0) {
        DslmDumper(fd);
    } else {
        dprintf(fd, "please use hidumper -s said -a -h command help\n");
    }

    return 0;
}

int32_t DslmService::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
    SetSystemAbilityUnloadSchedule(unloadTimerHandle_);

    do {
        if (IDeviceSecurityLevel::GetDescriptor() != data.ReadInterfaceToken()) {
            SECURITY_LOG_ERROR("local descriptor is not equal remote");
            break;
        }
        switch (code) {
            case CMD_GET_DEVICE_SECURITY_LEVEL:
                return ProcessGetDeviceSecurityLevel(data, reply);
            default:
                return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
        }
    } while (false);

    return ERR_REQUEST_CODE_ERR;
}

int32_t DslmService::RequestDeviceSecurityLevel(const DeviceIdentify &identify, const RequestOption &option,
    const sptr<IRemoteObject> &callback, uint64_t cookie)
    {
        return Singleton<DslmIpcProcess>::GetInstance().DslmProcessGetDeviceSecurityLevel(&identify, &option,
            cookie, callback);
    }

int32_t DslmService::ProcessGetDeviceSecurityLevel(MessageParcel &data, MessageParcel &reply)
{
    DeviceIdentify identify;
    RequestOption option;
    sptr<IRemoteObject> callback;
    uint32_t cookie;
    int32_t ret = Singleton<DslmIpcProcess>::GetInstance().DslmGetRequestFromParcel(data, identify, option,
        callback, cookie);
    if (ret != SUCCESS) {
        SECURITY_LOG_ERROR("DslmGetRequestFromParcel failed, ret is %{public}d", ret);
        return ret;
    }

    ret = RequestDeviceSecurityLevel(identify, option, callback, cookie);
    if (ret != SUCCESS) {
        SECURITY_LOG_ERROR("RequestDeviceSecurityLevel failed, ret is %{public}d", ret);
        return ret;
    }

    ret = Singleton<DslmIpcProcess>::GetInstance().DslmSetResponseToParcel(reply, cookie);
    if (ret != SUCCESS) {
        SECURITY_LOG_ERROR("DslmSetResponseToParcel failed, ret is %{public}d", ret);
        return ret;
    }

    return SUCCESS;
}

void DslmService::ProcessLoadPlugin(void)
{
#ifdef PLUGIN_SO_PATH
    handle_ = dlopen(PLUGIN_SO_PATH, RTLD_NOW);
    if (!handle_) {
        SECURITY_LOG_ERROR("load %{public}s failed for %{public}s", PLUGIN_SO_PATH, dlerror());
    }
#endif
}

void DslmService::ProcessUnloadPlugin(void)
{
#ifdef PLUGIN_SO_PATH
    if (handle_) {
        dlclose(handle_);
        SECURITY_LOG_INFO("unload %{public}s", PLUGIN_SO_PATH);
    }
#endif
}
} // namespace DeviceSecurityLevel
} // namespace Security
} // namespace OHOS