/* * Copyright (c) 2021-2023 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 "data_ability_manager.h" #include #include #include "ability_manager_service.h" #include "ability_util.h" #include "connection_state_manager.h" #include "hilog_wrapper.h" namespace OHOS { namespace AAFwk { using namespace std::chrono; using namespace std::placeholders; namespace { constexpr bool DEBUG_ENABLED = false; constexpr system_clock::duration DATA_ABILITY_LOAD_TIMEOUT = 11000ms; } // namespace DataAbilityManager::DataAbilityManager() { HILOG_DEBUG("Call"); } DataAbilityManager::~DataAbilityManager() { HILOG_DEBUG("Call"); } sptr DataAbilityManager::Acquire( const AbilityRequest &abilityRequest, bool tryBind, const sptr &client, bool isNotHap) { HILOG_DEBUG("Call"); if (abilityRequest.abilityInfo.type != AppExecFwk::AbilityType::DATA) { HILOG_ERROR("Data ability manager acquire: not a data ability."); return nullptr; } if (abilityRequest.abilityInfo.bundleName.empty() || abilityRequest.abilityInfo.name.empty()) { HILOG_ERROR("Data ability manager acquire: invalid name."); return nullptr; } std::shared_ptr clientAbilityRecord; const std::string dataAbilityName(abilityRequest.abilityInfo.bundleName + '.' + abilityRequest.abilityInfo.name); if (client && !isNotHap) { clientAbilityRecord = Token::GetAbilityRecordByToken(client); if (!clientAbilityRecord) { HILOG_ERROR("Data ability manager acquire: invalid client token."); return nullptr; } HILOG_INFO("Ability '%{public}s' acquiring data ability '%{public}s'...", clientAbilityRecord->GetAbilityInfo().name.c_str(), dataAbilityName.c_str()); } else { HILOG_INFO("Loading data ability '%{public}s'...", dataAbilityName.c_str()); } std::lock_guard locker(mutex_); if (DEBUG_ENABLED) { DumpLocked(__func__, __LINE__); } DataAbilityRecordPtr dataAbilityRecord; auto it = dataAbilityRecordsLoaded_.find(dataAbilityName); if (it == dataAbilityRecordsLoaded_.end()) { HILOG_DEBUG("Acquiring data ability is not existed, loading..."); dataAbilityRecord = LoadLocked(dataAbilityName, abilityRequest); } else { HILOG_DEBUG("Acquiring data ability is existed ."); dataAbilityRecord = it->second; } if (!dataAbilityRecord) { HILOG_ERROR("Failed to load data ability '%{public}s'.", dataAbilityName.c_str()); return nullptr; } auto scheduler = dataAbilityRecord->GetScheduler(); if (!scheduler) { if (DEBUG_ENABLED) { HILOG_ERROR("BUG: data ability '%{public}s' is not loaded, removing it...", dataAbilityName.c_str()); } auto it = dataAbilityRecordsLoaded_.find(dataAbilityName); if (it != dataAbilityRecordsLoaded_.end()) { dataAbilityRecordsLoaded_.erase(it); } return nullptr; } if (client) { dataAbilityRecord->AddClient(client, tryBind, isNotHap); } if (DEBUG_ENABLED) { DumpLocked(__func__, __LINE__); } ReportDataAbilityAcquired(client, isNotHap, dataAbilityRecord); return scheduler; } int DataAbilityManager::Release( const sptr &scheduler, const sptr &client, bool isNotHap) { HILOG_DEBUG("Call"); CHECK_POINTER_AND_RETURN(scheduler, ERR_NULL_OBJECT); CHECK_POINTER_AND_RETURN(client, ERR_NULL_OBJECT); std::lock_guard locker(mutex_); if (DEBUG_ENABLED) { DumpLocked(__func__, __LINE__); } DataAbilityRecordPtr dataAbilityRecord; for (auto it = dataAbilityRecordsLoaded_.begin(); it != dataAbilityRecordsLoaded_.end(); ++it) { if (it->second && it->second->GetScheduler() && it->second->GetScheduler()->AsObject() == scheduler->AsObject()) { dataAbilityRecord = it->second; HILOG_INFO("Releasing data ability '%{public}s'...", it->first.c_str()); break; } } if (!dataAbilityRecord) { HILOG_ERROR("Releasing not existed data ability."); return ERR_UNKNOWN_OBJECT; } auto abilityRecord = dataAbilityRecord->GetAbilityRecord(); CHECK_POINTER_AND_RETURN(abilityRecord, ERR_UNKNOWN_OBJECT); auto abilityMs = DelayedSingleton::GetInstance(); CHECK_POINTER_AND_RETURN(abilityMs, GET_ABILITY_SERVICE_FAILED); int result = abilityMs->JudgeAbilityVisibleControl(abilityRecord->GetAbilityInfo()); if (result != ERR_OK) { HILOG_ERROR("JudgeAbilityVisibleControl error."); return result; } if (dataAbilityRecord->GetClientCount(client) == 0) { HILOG_ERROR("Release data ability with wrong client."); return ERR_UNKNOWN_OBJECT; } dataAbilityRecord->RemoveClient(client, isNotHap); if (DEBUG_ENABLED) { DumpLocked(__func__, __LINE__); } ReportDataAbilityReleased(client, isNotHap, dataAbilityRecord); return ERR_OK; } bool DataAbilityManager::ContainsDataAbility(const sptr &scheduler) { HILOG_DEBUG("Call"); CHECK_POINTER_AND_RETURN(scheduler, ERR_NULL_OBJECT); std::lock_guard locker(mutex_); for (auto it = dataAbilityRecordsLoaded_.begin(); it != dataAbilityRecordsLoaded_.end(); ++it) { if (it->second && it->second->GetScheduler() && it->second->GetScheduler()->AsObject() == scheduler->AsObject()) { return true; } } return false; } int DataAbilityManager::AttachAbilityThread(const sptr &scheduler, const sptr &token) { HILOG_DEBUG("Call"); CHECK_POINTER_AND_RETURN(scheduler, ERR_NULL_OBJECT); CHECK_POINTER_AND_RETURN(token, ERR_NULL_OBJECT); std::lock_guard locker(mutex_); if (DEBUG_ENABLED) { DumpLocked(__func__, __LINE__); } HILOG_INFO("Attaching data ability..."); auto record = Token::GetAbilityRecordByToken(token); std::string abilityName = ""; if (record != nullptr) { abilityName = record->GetAbilityInfo().name; } DataAbilityRecordPtr dataAbilityRecord; auto it = dataAbilityRecordsLoading_.begin(); for (; it != dataAbilityRecordsLoading_.end(); ++it) { if (it->second && it->second->GetToken() == token) { dataAbilityRecord = it->second; break; } } if (!dataAbilityRecord) { HILOG_ERROR("Attaching data ability '%{public}s' is not in loading state.", abilityName.c_str()); return ERR_UNKNOWN_OBJECT; } if (DEBUG_ENABLED && dataAbilityRecord->GetClientCount() > 0) { HILOG_ERROR("BUG: Attaching data ability '%{public}s' has clients.", abilityName.c_str()); } if (DEBUG_ENABLED && dataAbilityRecord->GetScheduler()) { HILOG_ERROR("BUG: Attaching data ability '%{public}s' has ready.", abilityName.c_str()); } if (DEBUG_ENABLED && dataAbilityRecordsLoaded_.count(it->first) != 0) { HILOG_ERROR("BUG: The attaching data ability '%{public}s' has already existed.", abilityName.c_str()); } return dataAbilityRecord->Attach(scheduler); } int DataAbilityManager::AbilityTransitionDone(const sptr &token, int state) { HILOG_DEBUG("Call"); CHECK_POINTER_AND_RETURN(token, ERR_NULL_OBJECT); std::lock_guard locker(mutex_); if (DEBUG_ENABLED) { DumpLocked(__func__, __LINE__); } HILOG_INFO("Handling data ability transition done %{public}d...", state); DataAbilityRecordPtrMap::iterator it; DataAbilityRecordPtr dataAbilityRecord; auto record = Token::GetAbilityRecordByToken(token); std::string abilityName = ""; if (record != nullptr) { abilityName = record->GetAbilityInfo().name; } for (it = dataAbilityRecordsLoading_.begin(); it != dataAbilityRecordsLoading_.end(); ++it) { if (it->second && it->second->GetToken() == token) { dataAbilityRecord = it->second; break; } } if (!dataAbilityRecord) { HILOG_ERROR("Attaching data ability '%{public}s' is not existed.", abilityName.c_str()); return ERR_UNKNOWN_OBJECT; } int ret = dataAbilityRecord->OnTransitionDone(state); if (ret == ERR_OK) { dataAbilityRecordsLoaded_[it->first] = dataAbilityRecord; dataAbilityRecordsLoading_.erase(it); } return ret; } void DataAbilityManager::OnAbilityRequestDone(const sptr &token, const int32_t state) { /* Do nothing now. */ } void DataAbilityManager::OnAbilityDied(const std::shared_ptr &abilityRecord) { HILOG_INFO("Call"); CHECK_POINTER(abilityRecord); { std::lock_guard locker(mutex_); if (DEBUG_ENABLED) { DumpLocked(__func__, __LINE__); } if (abilityRecord->GetAbilityInfo().type == AppExecFwk::AbilityType::DATA) { // If 'abilityRecord' is a data ability server, trying to remove it from 'dataAbilityRecords_'. for (auto it = dataAbilityRecordsLoaded_.begin(); it != dataAbilityRecordsLoaded_.end();) { if (it->second && it->second->GetAbilityRecord() == abilityRecord) { DelayedSingleton::GetInstance()->HandleDataAbilityDied(it->second); it->second->KillBoundClientProcesses(); HILOG_DEBUG("Removing died data ability record..."); it = dataAbilityRecordsLoaded_.erase(it); break; } else { ++it; } } } if (DEBUG_ENABLED) { DumpLocked(__func__, __LINE__); } // If 'abilityRecord' is a data ability client, tring to remove it from all servers. for (auto it = dataAbilityRecordsLoaded_.begin(); it != dataAbilityRecordsLoaded_.end(); ++it) { if (it->second) { it->second->RemoveClients(abilityRecord); } } if (DEBUG_ENABLED) { DumpLocked(__func__, __LINE__); } } RestartDataAbility(abilityRecord); } void DataAbilityManager::OnAppStateChanged(const AppInfo &info) { std::lock_guard locker(mutex_); for (auto it = dataAbilityRecordsLoaded_.begin(); it != dataAbilityRecordsLoaded_.end(); ++it) { if (!it->second) { continue; } auto abilityRecord = it->second->GetAbilityRecord(); if (abilityRecord && (info.processName == abilityRecord->GetAbilityInfo().process || info.processName == abilityRecord->GetApplicationInfo().bundleName)) { auto appName = abilityRecord->GetApplicationInfo().name; auto uid = abilityRecord->GetAbilityInfo().applicationInfo.uid; auto isExist = [&appName, &uid]( const AppData &appData) { return appData.appName == appName && appData.uid == uid; }; auto iter = std::find_if(info.appData.begin(), info.appData.end(), isExist); if (iter != info.appData.end()) { abilityRecord->SetAppState(info.state); } } } for (auto it = dataAbilityRecordsLoading_.begin(); it != dataAbilityRecordsLoading_.end(); ++it) { if (!it->second) { continue; } auto abilityRecord = it->second->GetAbilityRecord(); if (abilityRecord && (info.processName == abilityRecord->GetAbilityInfo().process || info.processName == abilityRecord->GetApplicationInfo().bundleName)) { auto appName = abilityRecord->GetApplicationInfo().name; auto uid = abilityRecord->GetAbilityInfo().applicationInfo.uid; auto isExist = [&appName, &uid]( const AppData &appData) { return appData.appName == appName && appData.uid == uid; }; auto iter = std::find_if(info.appData.begin(), info.appData.end(), isExist); if (iter != info.appData.end()) { abilityRecord->SetAppState(info.state); } } } } std::shared_ptr DataAbilityManager::GetAbilityRecordById(int64_t id) { HILOG_DEBUG("Call."); std::lock_guard locker(mutex_); for (auto it = dataAbilityRecordsLoaded_.begin(); it != dataAbilityRecordsLoaded_.end(); ++it) { if (!it->second) { continue; } auto abilityRecord = it->second->GetAbilityRecord(); if (abilityRecord->GetRecordId() == id) { return abilityRecord; } } return nullptr; } std::shared_ptr DataAbilityManager::GetAbilityRecordByToken(const sptr &token) { HILOG_DEBUG("Call."); CHECK_POINTER_AND_RETURN(token, nullptr); std::lock_guard locker(mutex_); for (auto it = dataAbilityRecordsLoaded_.begin(); it != dataAbilityRecordsLoaded_.end(); ++it) { if (!it->second) { continue; } auto abilityRecord = it->second->GetAbilityRecord(); if (abilityRecord == Token::GetAbilityRecordByToken(token)) { return abilityRecord; } } for (auto it = dataAbilityRecordsLoading_.begin(); it != dataAbilityRecordsLoading_.end(); ++it) { if (!it->second) { continue; } auto abilityRecord = it->second->GetAbilityRecord(); if (abilityRecord == Token::GetAbilityRecordByToken(token)) { return abilityRecord; } } return nullptr; } std::shared_ptr DataAbilityManager::GetAbilityRecordByScheduler(const sptr &scheduler) { HILOG_DEBUG("Call."); CHECK_POINTER_AND_RETURN(scheduler, nullptr); std::lock_guard locker(mutex_); for (auto it = dataAbilityRecordsLoaded_.begin(); it != dataAbilityRecordsLoaded_.end(); ++it) { if (it->second && it->second->GetScheduler() && it->second->GetScheduler()->AsObject() == scheduler->AsObject()) { return it->second->GetAbilityRecord(); } } return nullptr; } void DataAbilityManager::Dump(const char *func, int line) { HILOG_DEBUG("Call."); std::lock_guard locker(mutex_); DumpLocked(func, line); } DataAbilityManager::DataAbilityRecordPtr DataAbilityManager::LoadLocked( const std::string &name, const AbilityRequest &req) { HILOG_DEBUG("name '%{public}s'", name.c_str()); DataAbilityRecordPtr dataAbilityRecord; auto it = dataAbilityRecordsLoading_.find(name); if (it == dataAbilityRecordsLoading_.end()) { HILOG_INFO("Acquiring data ability is not in loading, trying to load it..."); dataAbilityRecord = std::make_shared(req); // Start data ability loading process asynchronously. int startResult = dataAbilityRecord->StartLoading(); if (startResult != ERR_OK) { HILOG_ERROR("Failed to load data ability %{public}d", startResult); return nullptr; } auto insertResult = dataAbilityRecordsLoading_.insert({name, dataAbilityRecord}); if (!insertResult.second) { HILOG_ERROR("Failed to insert data ability to loading map."); return nullptr; } } else { HILOG_INFO("Acquired data ability is loading..."); dataAbilityRecord = it->second; } if (!dataAbilityRecord) { HILOG_ERROR("Failed to load data ability '%{public}s'.", name.c_str()); return nullptr; } HILOG_INFO("Waiting for data ability loaded..."); // Waiting for data ability loaded. int ret = dataAbilityRecord->WaitForLoaded(mutex_, DATA_ABILITY_LOAD_TIMEOUT); if (ret != ERR_OK) { HILOG_ERROR("Wait for data ability failed %{public}d.", ret); it = dataAbilityRecordsLoading_.find(name); if (it != dataAbilityRecordsLoading_.end()) { dataAbilityRecordsLoading_.erase(it); } DelayedSingleton::GetInstance()->AttachTimeOut(dataAbilityRecord->GetToken()); return nullptr; } return dataAbilityRecord; } void DataAbilityManager::DumpLocked(const char *func, int line) { if (func && line >= 0) { HILOG_INFO("Data ability manager dump at %{public}s(%{public}d)", func, line); } else { HILOG_INFO("Data ability manager dump"); } HILOG_INFO("Available data ability count: %{public}zu", dataAbilityRecordsLoaded_.size()); for (auto it = dataAbilityRecordsLoaded_.begin(); it != dataAbilityRecordsLoaded_.end(); ++it) { HILOG_INFO("'%{public}s':", it->first.c_str()); if (it->second) { it->second->Dump(); } } HILOG_INFO("Loading data ability count: %{public}zu", dataAbilityRecordsLoading_.size()); for (auto it = dataAbilityRecordsLoading_.begin(); it != dataAbilityRecordsLoading_.end(); ++it) { HILOG_INFO("'%{public}s':", it->first.c_str()); if (it->second) { it->second->Dump(); } } } void DataAbilityManager::DumpState(std::vector &info, const std::string &args) const { DataAbilityRecordPtrMap dataAbilityRecordMap; { std::lock_guard locker(mutex_); dataAbilityRecordMap = dataAbilityRecordsLoaded_; } if (!args.empty()) { auto it = std::find_if(dataAbilityRecordMap.begin(), dataAbilityRecordMap.end(), [&args](const auto &dataAbilityRecord) { return dataAbilityRecord.first.compare(args) == 0; }); if (it != dataAbilityRecordMap.end()) { info.emplace_back("AbilityName [ " + it->first + " ]"); if (it->second) { it->second->Dump(info); } } else { info.emplace_back(args + ": Nothing to dump."); } } else { info.emplace_back("dataAbilityRecords:"); for (auto &&dataAbilityRecord : dataAbilityRecordMap) { info.emplace_back(" uri [" + dataAbilityRecord.first + "]"); if (dataAbilityRecord.second) { dataAbilityRecord.second->Dump(info); } } } } void DataAbilityManager::DumpClientInfo(std::vector &info, bool isClient, std::shared_ptr record) const { if (record == nullptr) { return; } record->Dump(info); // add dump client info if (isClient && record->GetScheduler() && record->GetAbilityRecord() && record->GetAbilityRecord()->IsReady()) { std::vector params; record->GetScheduler()->DumpAbilityInfo(params, info); AppExecFwk::Configuration config; if (DelayedSingleton::GetInstance()->GetConfiguration(config) == ERR_OK) { info.emplace_back(" configuration: " + config.GetName()); } return; } } void DataAbilityManager::DumpSysState(std::vector &info, bool isClient, const std::string &args) const { DataAbilityRecordPtrMap dataAbilityRecordMap; { std::lock_guard locker(mutex_); dataAbilityRecordMap = dataAbilityRecordsLoaded_; } if (args.empty()) { info.emplace_back(" dataAbilityRecords:"); for (auto &&dataAbilityRecord : dataAbilityRecordMap) { info.emplace_back(" uri [" + dataAbilityRecord.first + "]"); DumpClientInfo(info, isClient, dataAbilityRecord.second); } return; } auto compareFunction = [&args](const auto &dataAbilityRecord) { return dataAbilityRecord.first.compare(args) == 0; }; auto it = std::find_if(dataAbilityRecordMap.begin(), dataAbilityRecordMap.end(), compareFunction); if (it == dataAbilityRecordMap.end()) { info.emplace_back(args + ": Nothing to dump."); return; } info.emplace_back("AbilityName [ " + it->first + " ]"); DumpClientInfo(info, isClient, it->second); } void DataAbilityManager::GetAbilityRunningInfos(std::vector &info, bool isPerm) { HILOG_INFO("Get ability running infos"); std::lock_guard locker(mutex_); auto queryInfo = [&info, isPerm](DataAbilityRecordPtrMap::reference data) { auto dataAbilityRecord = data.second; if (!dataAbilityRecord) { return; } auto abilityRecord = dataAbilityRecord->GetAbilityRecord(); if (!abilityRecord) { return; } if (isPerm) { DelayedSingleton::GetInstance()->GetAbilityRunningInfo(info, abilityRecord); } else { auto callingTokenId = IPCSkeleton::GetCallingTokenID(); auto tokenID = abilityRecord->GetApplicationInfo().accessTokenId; if (callingTokenId == tokenID) { DelayedSingleton::GetInstance()->GetAbilityRunningInfo(info, abilityRecord); } } }; std::for_each(dataAbilityRecordsLoading_.begin(), dataAbilityRecordsLoading_.end(), queryInfo); std::for_each(dataAbilityRecordsLoaded_.begin(), dataAbilityRecordsLoaded_.end(), queryInfo); } void DataAbilityManager::RestartDataAbility(const std::shared_ptr &abilityRecord) { // restart data ability if necessary auto bundleMgrHelper = AbilityUtil::GetBundleManagerHelper(); CHECK_POINTER(bundleMgrHelper); std::vector bundleInfos; bool getBundleInfos = bundleMgrHelper->GetBundleInfos( OHOS::AppExecFwk::GET_BUNDLE_DEFAULT, bundleInfos, USER_ID_NO_HEAD); if (!getBundleInfos) { HILOG_ERROR("Handle ability died task, get bundle infos failed."); return; } for (size_t i = 0; i < bundleInfos.size(); i++) { if (!bundleInfos[i].isKeepAlive || bundleInfos[i].applicationInfo.process.empty()) { continue; } for (auto hapModuleInfo : bundleInfos[i].hapModuleInfos) { if (hapModuleInfo.isModuleJson) { // new application model, it cannot be a data ability continue; } // old application model, it maybe a data ability std::string mainElement = hapModuleInfo.mainAbility; if (abilityRecord->GetAbilityInfo().name != mainElement || abilityRecord->GetAbilityInfo().process != bundleInfos[i].applicationInfo.process) { continue; } std::string uriStr; bool getDataAbilityUri = OHOS::DelayedSingleton::GetInstance()->GetDataAbilityUri( hapModuleInfo.abilityInfos, mainElement, uriStr); if (getDataAbilityUri) { HILOG_INFO("restart data ability: %{public}s, uri: %{public}s.", abilityRecord->GetAbilityInfo().name.c_str(), uriStr.c_str()); Uri uri(uriStr); OHOS::DelayedSingleton::GetInstance()->AcquireDataAbility(uri, true, nullptr); return; } } } } void DataAbilityManager::ReportDataAbilityAcquired(const sptr &client, bool isNotHap, std::shared_ptr &record) { DataAbilityCaller caller; caller.isNotHap = isNotHap; caller.callerPid = IPCSkeleton::GetCallingPid(); caller.callerUid = IPCSkeleton::GetCallingUid(); caller.callerToken = client; if (client && !isNotHap) { auto abilityRecord = Token::GetAbilityRecordByToken(client); if (abilityRecord) { caller.callerName = abilityRecord->GetAbilityInfo().bundleName; } } else { caller.callerName = ConnectionStateManager::GetProcessNameByPid(caller.callerPid); } DelayedSingleton::GetInstance()->AddDataAbilityConnection(caller, record); } void DataAbilityManager::ReportDataAbilityReleased(const sptr &client, bool isNotHap, std::shared_ptr &record) { DataAbilityCaller caller; caller.isNotHap = isNotHap; caller.callerPid = IPCSkeleton::GetCallingPid(); caller.callerUid = IPCSkeleton::GetCallingUid(); caller.callerToken = client; DelayedSingleton::GetInstance()->RemoveDataAbilityConnection(caller, record); } } // namespace AAFwk } // namespace OHOS