/* * Copyright (c) 2021-2024 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 "dataobs_mgr_inner_pref.h" #include "data_ability_observer_stub.h" #include "dataobs_mgr_errors.h" #include "hilog_tag_wrapper.h" #include "common_utils.h" namespace OHOS { namespace AAFwk { DataObsMgrInnerPref::DataObsMgrInnerPref() {} DataObsMgrInnerPref::~DataObsMgrInnerPref() {} int DataObsMgrInnerPref::HandleRegisterObserver(const Uri &uri, sptr dataObserver) { std::lock_guard lock(preferenceMutex_); auto [obsPair, flag] = observers_.try_emplace(uri.ToString(), std::list>()); if (!flag && obsPair->second.size() > OBS_NUM_MAX) { TAG_LOGE(AAFwkTag::DBOBSMGR, "subscribers num:%{public}s num maxed", CommonUtils::Anonymous(uri.ToString()).c_str()); return DATAOBS_SERVICE_OBS_LIMMIT; } for (auto obs = obsPair->second.begin(); obs != obsPair->second.end(); obs++) { if ((*obs)->AsObject() == dataObserver->AsObject()) { TAG_LOGE(AAFwkTag::DBOBSMGR, "registered obs:%{public}s", CommonUtils::Anonymous(uri.ToString()).c_str()); return OBS_EXIST; } } obsPair->second.push_back(dataObserver); AddObsDeathRecipient(dataObserver); return NO_ERROR; } int DataObsMgrInnerPref::HandleUnregisterObserver(const Uri &uri, sptr dataObserver) { std::lock_guard lock(preferenceMutex_); auto obsPair = observers_.find(uri.ToString()); if (obsPair == observers_.end()) { TAG_LOGW( AAFwkTag::DBOBSMGR, "uris no obs:%{public}s", CommonUtils::Anonymous(uri.ToString()).c_str()); return NO_OBS_FOR_URI; } TAG_LOGD(AAFwkTag::DBOBSMGR, "obs num:%{public}zu:%{public}s", obsPair->second.size(), CommonUtils::Anonymous(uri.ToString()).c_str()); auto obs = obsPair->second.begin(); for (; obs != obsPair->second.end(); obs++) { if ((*obs)->AsObject() == dataObserver->AsObject()) { break; } } if (obs == obsPair->second.end()) { TAG_LOGW( AAFwkTag::DBOBSMGR, "uris no obs:%{public}s", CommonUtils::Anonymous(uri.ToString()).c_str()); return NO_OBS_FOR_URI; } obsPair->second.remove(*obs); if (obsPair->second.empty()) { observers_.erase(obsPair); } if (!HaveRegistered(dataObserver)) { RemoveObsDeathRecipient(dataObserver->AsObject()); } return NO_ERROR; } int DataObsMgrInnerPref::HandleNotifyChange(const Uri &uri) { std::list> obsList; std::lock_guard lock(preferenceMutex_); { std::string uriStr = uri.ToString(); size_t pos = uriStr.find('?'); if (pos == std::string::npos) { TAG_LOGW(AAFwkTag::DBOBSMGR, "uri missing query:%{public}s", CommonUtils::Anonymous(uriStr).c_str()); return INVALID_PARAM; } std::string observerKey = uriStr.substr(0, pos); auto obsPair = observers_.find(observerKey); if (obsPair == observers_.end()) { TAG_LOGD(AAFwkTag::DBOBSMGR, "uri no obs:%{public}s", CommonUtils::Anonymous(uri.ToString()).c_str()); return NO_OBS_FOR_URI; } obsList = obsPair->second; } for (auto &obs : obsList) { if (obs != nullptr) { obs->OnChangePreferences(const_cast(uri).GetQuery()); } } TAG_LOGD(AAFwkTag::DBOBSMGR, "uri end:%{public}s,obs num:%{public}zu", CommonUtils::Anonymous(uri.ToString()).c_str(), obsList.size()); return NO_ERROR; } void DataObsMgrInnerPref::AddObsDeathRecipient(sptr dataObserver) { if ((dataObserver == nullptr) || dataObserver->AsObject() == nullptr) { return; } auto it = obsRecipient_.find(dataObserver->AsObject()); if (it != obsRecipient_.end()) { TAG_LOGW(AAFwkTag::DBOBSMGR, "called"); return; } else { std::weak_ptr thisWeakPtr(shared_from_this()); sptr deathRecipient = new DataObsCallbackRecipient([thisWeakPtr](const wptr &remote) { auto dataObsMgrInner = thisWeakPtr.lock(); if (dataObsMgrInner) { dataObsMgrInner->OnCallBackDied(remote); } }); if (!dataObserver->AsObject()->AddDeathRecipient(deathRecipient)) { TAG_LOGE(AAFwkTag::DBOBSMGR, "failed"); } obsRecipient_.emplace(dataObserver->AsObject(), deathRecipient); } } void DataObsMgrInnerPref::RemoveObsDeathRecipient(sptr dataObserver) { if (dataObserver == nullptr) { return; } auto it = obsRecipient_.find(dataObserver); if (it != obsRecipient_.end()) { it->first->RemoveDeathRecipient(it->second); obsRecipient_.erase(it); return; } } void DataObsMgrInnerPref::OnCallBackDied(const wptr &remote) { auto dataObserver = remote.promote(); if (dataObserver == nullptr) { return; } std::lock_guard lock(preferenceMutex_); if (dataObserver == nullptr) { TAG_LOGE(AAFwkTag::DBOBSMGR, "null dataObserver"); return; } RemoveObs(dataObserver); } void DataObsMgrInnerPref::RemoveObs(sptr dataObserver) { for (auto iter = observers_.begin(); iter != observers_.end();) { auto &obsList = iter->second; for (auto it = obsList.begin(); it != obsList.end(); it++) { if ((*it)->AsObject() == dataObserver) { TAG_LOGD(AAFwkTag::DBOBSMGR, "erase"); obsList.erase(it); break; } } if (obsList.size() == 0) { iter = observers_.erase(iter); } else { iter++; } } RemoveObsDeathRecipient(dataObserver); } bool DataObsMgrInnerPref::HaveRegistered(sptr dataObserver) { for (auto &[key, value] : observers_) { auto obs = std::find(value.begin(), value.end(), dataObserver); if (obs != value.end()) { return true; } } return false; } } // namespace AAFwk } // namespace OHOS