/*

 * Copyright (c) 2022-2026 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 "bundle_manager_helper.h"



#include "accesstoken_kit.h"

#include "iservice_registry.h"

#include "system_ability_definition.h"

#include "tokenid_kit.h"



#include "continuous_task_log.h"



namespace OHOS {

namespace BackgroundTaskMgr {

#ifdef BGTASK_MGR_UNIT_TEST

#define WEAK_FUNC __attribute__((weak))

#else

#define WEAK_FUNC

#endif



using OHOS::AppExecFwk::Constants::PERMISSION_GRANTED;



BundleManagerHelper::BundleManagerHelper()

{

    bundleMgrDeathRecipient_ = new (std::nothrow) RemoteDeathRecipient(

        [this](const wptr<IRemoteObject> &object) { this->OnRemoteDied(object); });

}



BundleManagerHelper::~BundleManagerHelper()

{

    std::lock_guard<std::mutex> lock(connectionMutex_);

    Disconnect();

}



std::string BundleManagerHelper::GetClientBundleName(int32_t uid)

{

    std::string bundle {""};

    std::lock_guard<std::mutex> lock(connectionMutex_);

    Connect();

    if (bundleMgr_ != nullptr) {

        bundleMgr_->GetNameForUid(uid, bundle);

    }

    BGTASK_LOGD("get client Bundle Name: %{public}s", bundle.c_str());

    return bundle;

}



bool BundleManagerHelper::CheckPermission(const std::string &permission)

{

    Security::AccessToken::AccessTokenID callerToken = IPCSkeleton::GetCallingTokenID();

    int32_t ret = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callerToken, permission);

    if (ret != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {

        BGTASK_LOGE("CheckPermission: %{public}s failed", permission.c_str());

        return false;

    }

    return true;

}



bool BundleManagerHelper::CheckACLPermission(const std::string &permission, uint64_t callingTokenId)

{

    int32_t ret = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callingTokenId, permission);

    if (ret != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {

        BGTASK_LOGD("CheckPermission: %{public}s failed", permission.c_str());

        return false;

    }

    return true;

}



bool BundleManagerHelper::IsSystemApp(uint64_t fullTokenId)

{

    return Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(fullTokenId);

}



bool BundleManagerHelper::GetBundleInfo(const std::string &bundleName, const AppExecFwk::BundleFlag flag,

    AppExecFwk::BundleInfo &bundleInfo, int32_t userId)

{

    std::lock_guard<std::mutex> lock(connectionMutex_);



    Connect();



    if (bundleMgr_ != nullptr && bundleMgr_->GetBundleInfo(bundleName, flag, bundleInfo, userId)) {

        return true;

    }

    return false;

}



bool WEAK_FUNC BundleManagerHelper::GetApplicationInfo(const std::string &appName,

    const AppExecFwk::ApplicationFlag flag, const int userId, AppExecFwk::ApplicationInfo &appInfo)

{

    BGTASK_LOGD("start get application info");

    std::lock_guard<std::mutex> lock(connectionMutex_);



    Connect();

    BGTASK_LOGD("bundleMgr is null: %{public}d ", bundleMgr_ == nullptr);

    if (bundleMgr_ != nullptr && bundleMgr_->GetApplicationInfo(appName, flag, userId, appInfo)) {

        return true;

    }

    return false;

}



bool BundleManagerHelper::QueryAbilityInfo(const AAFwk::Want &want, int32_t flags, int32_t userId,

    AppExecFwk::AbilityInfo &abilityInfo)

{

    std::lock_guard<std::mutex> lock(connectionMutex_);

    Connect();

    if (bundleMgr_ != nullptr && bundleMgr_->QueryAbilityInfo(want, flags, userId, abilityInfo)) {

        return true;

    }

    return false;

}



bool BundleManagerHelper::GetBundleResourceInfo(const std::string &bundleName, const AppExecFwk::ResourceFlag flags,

    AppExecFwk::BundleResourceInfo &bundleResourceInfo)

{

    std::lock_guard<std::mutex> lock(connectionMutex_);

    Connect();

    if (bundleMgr_ == nullptr) {

        return false;

    }

    sptr<AppExecFwk::IBundleResource> bundleResourceProxy = bundleMgr_->GetBundleResourceProxy();

    if (bundleResourceProxy == nullptr) {

        return false;

    }

    ErrCode result = bundleResourceProxy->

        GetBundleResourceInfo(bundleName, static_cast<uint32_t>(flags), bundleResourceInfo);

    if (result != ERR_OK) {

        BGTASK_LOGE("GetBundleResourceInfo fail, errcode: %{public}d", result);

        return false;

    }

    return true;

}



bool BundleManagerHelper::GetBundleInfoByFlags(const std::string &bundleName, int32_t flags,

    AppExecFwk::BundleInfo &bundleInfo, int32_t userId)

{

    std::lock_guard<std::mutex> lock(connectionMutex_);



    Connect();



    if (bundleMgr_ != nullptr && bundleMgr_->GetBundleInfo(bundleName, flags, bundleInfo, userId)) {

        return true;

    }

    return false;

}



bool BundleManagerHelper::GetAppIndexAndBundleNameByUid(int32_t uid, int32_t &appIndex, std::string &bundleName)

{

    std::lock_guard<std::mutex> lock(connectionMutex_);

    Connect();

    if (bundleMgr_ == nullptr) {

        return false;

    }

    ErrCode ret = bundleMgr_->GetNameAndIndexForUid(uid, bundleName, appIndex);

    if (ret == ERR_OK) {

        return true;

    }

    return false;

}



bool BundleManagerHelper::Connect()

{

    if (bundleMgr_ != nullptr) {

        return true;

    }



    sptr<ISystemAbilityManager> systemAbilityManager =

        SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();

    if (systemAbilityManager == nullptr) {

        BGTASK_LOGE("get SystemAbilityManager failed");

        return false;

    }



    sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);

    if (remoteObject == nullptr) {

        BGTASK_LOGE("get Bundle Manager failed");

        return false;

    }



    bundleMgr_ = iface_cast<AppExecFwk::IBundleMgr>(remoteObject);

    if (bundleMgr_ != nullptr && bundleMgrDeathRecipient_ != nullptr) {

        bundleMgr_->AsObject()->AddDeathRecipient(bundleMgrDeathRecipient_);

        return true;

    }

    BGTASK_LOGE("get bundleMgr failed");

    return false;

}



void BundleManagerHelper::Disconnect()

{

    if (bundleMgr_ != nullptr && bundleMgr_->AsObject() != nullptr) {

        bundleMgr_->AsObject()->RemoveDeathRecipient(bundleMgrDeathRecipient_);

        bundleMgr_ = nullptr;

    }

}



void BundleManagerHelper::OnRemoteDied(const wptr<IRemoteObject> &object)

{

    std::lock_guard<std::mutex> lock(connectionMutex_);

    Disconnect();

}

}  // namespace BackgroundTaskMgr

}  // namespace OHOS