diff options
Diffstat (limited to 'gps/core/SystemStatusOsObserver.cpp')
-rw-r--r-- | gps/core/SystemStatusOsObserver.cpp | 592 |
1 files changed, 592 insertions, 0 deletions
diff --git a/gps/core/SystemStatusOsObserver.cpp b/gps/core/SystemStatusOsObserver.cpp new file mode 100644 index 0000000..8fd9564 --- /dev/null +++ b/gps/core/SystemStatusOsObserver.cpp @@ -0,0 +1,592 @@ +/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation, nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#define LOG_TAG "LocSvc_SystemStatusOsObserver" + +#include <algorithm> +#include <SystemStatus.h> +#include <SystemStatusOsObserver.h> +#include <IDataItemCore.h> +#include <DataItemsFactoryProxy.h> + +namespace loc_core +{ +template <typename CINT, typename COUT> +COUT SystemStatusOsObserver::containerTransfer(CINT& inContainer) { + COUT outContainer = {}; + for (auto item : inContainer) { + outContainer.insert(outContainer.begin(), item); + } + return outContainer; +} + +SystemStatusOsObserver::~SystemStatusOsObserver() { + // Close data-item library handle + DataItemsFactoryProxy::closeDataItemLibraryHandle(); + + // Destroy cache + for (auto each : mDataItemCache) { + if (nullptr != each.second) { + delete each.second; + } + } + + mDataItemCache.clear(); +} + +void SystemStatusOsObserver::setSubscriptionObj(IDataItemSubscription* subscriptionObj) +{ + struct SetSubsObj : public LocMsg { + ObserverContext& mContext; + IDataItemSubscription* mSubsObj; + inline SetSubsObj(ObserverContext& context, IDataItemSubscription* subscriptionObj) : + mContext(context), mSubsObj(subscriptionObj) {} + void proc() const { + LOC_LOGi("SetSubsObj::enter"); + mContext.mSubscriptionObj = mSubsObj; + + if (!mContext.mSSObserver->mDataItemToClients.empty()) { + list<DataItemId> dis( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + mContext.mSSObserver->mDataItemToClients.getKeys())); + mContext.mSubscriptionObj->subscribe(dis, mContext.mSSObserver); + mContext.mSubscriptionObj->requestData(dis, mContext.mSSObserver); + } + LOC_LOGi("SetSubsObj::exit"); + } + }; + + if (nullptr == subscriptionObj) { + LOC_LOGw("subscriptionObj is NULL"); + } else { + mContext.mMsgTask->sendMsg(new SetSubsObj(mContext, subscriptionObj)); + } +} + +/****************************************************************************** + IDataItemSubscription Overrides +******************************************************************************/ +void SystemStatusOsObserver::subscribe(const list<DataItemId>& l, IDataItemObserver* client, + bool toRequestData) +{ + struct HandleSubscribeReq : public LocMsg { + inline HandleSubscribeReq(SystemStatusOsObserver* parent, + list<DataItemId>& l, IDataItemObserver* client, bool requestData) : + mParent(parent), mClient(client), + mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)), + diItemlist(l), + mToRequestData(requestData) {} + + void proc() const { + unordered_set<DataItemId> dataItemsToSubscribe = {}; + mParent->mDataItemToClients.add(mDataItemSet, {mClient}, &dataItemsToSubscribe); + mParent->mClientToDataItems.add(mClient, mDataItemSet); + + mParent->sendCachedDataItems(mDataItemSet, mClient); + + // Send subscription set to framework + if (nullptr != mParent->mContext.mSubscriptionObj) { + if (mToRequestData) { + LOC_LOGD("Request Data sent to framework for the following"); + mParent->mContext.mSubscriptionObj->requestData(diItemlist, mParent); + } else if (!dataItemsToSubscribe.empty()) { + LOC_LOGD("Subscribe Request sent to framework for the following"); + mParent->logMe(dataItemsToSubscribe); + mParent->mContext.mSubscriptionObj->subscribe( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + std::move(dataItemsToSubscribe)), + mParent); + } + } + } + mutable SystemStatusOsObserver* mParent; + IDataItemObserver* mClient; + const unordered_set<DataItemId> mDataItemSet; + const list<DataItemId> diItemlist; + bool mToRequestData; + }; + + if (l.empty() || nullptr == client) { + LOC_LOGw("Data item set is empty or client is nullptr"); + } else { + mContext.mMsgTask->sendMsg( + new HandleSubscribeReq(this, (list<DataItemId>&)l, client, toRequestData)); + } +} + +void SystemStatusOsObserver::updateSubscription( + const list<DataItemId>& l, IDataItemObserver* client) +{ + struct HandleUpdateSubscriptionReq : public LocMsg { + HandleUpdateSubscriptionReq(SystemStatusOsObserver* parent, + list<DataItemId>& l, IDataItemObserver* client) : + mParent(parent), mClient(client), + mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {} + + void proc() const { + unordered_set<DataItemId> dataItemsToSubscribe = {}; + unordered_set<DataItemId> dataItemsToUnsubscribe = {}; + unordered_set<IDataItemObserver*> clients({mClient}); + // below removes clients from all entries keyed with the return of the + // mClientToDataItems.update() call. If leaving an empty set of clients as the + // result, the entire entry will be removed. dataItemsToUnsubscribe will be + // populated to keep the keys of the removed entries. + mParent->mDataItemToClients.trimOrRemove( + // this call updates <IDataItemObserver*, DataItemId> map; removes + // the DataItemId's that are not new to the clietn from mDataItemSet; + // and returns a set of mDataItemSet's that are no longer used by client. + // This unused set of mDataItemSet's is passed to trimOrRemove method of + // <DataItemId, IDataItemObserver*> map to remove the client from the + // corresponding entries, and gets a set of the entries that are + // removed from the <DataItemId, IDataItemObserver*> map as a result. + mParent->mClientToDataItems.update(mClient, + (unordered_set<DataItemId>&)mDataItemSet), + clients, &dataItemsToUnsubscribe, nullptr); + // below adds mClient to <DataItemId, IDataItemObserver*> map, and populates + // new keys added to that map, which are DataItemIds to be subscribed. + mParent->mDataItemToClients.add(mDataItemSet, clients, &dataItemsToSubscribe); + + // Send First Response + mParent->sendCachedDataItems(mDataItemSet, mClient); + + if (nullptr != mParent->mContext.mSubscriptionObj) { + // Send subscription set to framework + if (!dataItemsToSubscribe.empty()) { + LOC_LOGD("Subscribe Request sent to framework for the following"); + mParent->logMe(dataItemsToSubscribe); + + mParent->mContext.mSubscriptionObj->subscribe( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + std::move(dataItemsToSubscribe)), + mParent); + } + + // Send unsubscribe to framework + if (!dataItemsToUnsubscribe.empty()) { + LOC_LOGD("Unsubscribe Request sent to framework for the following"); + mParent->logMe(dataItemsToUnsubscribe); + + mParent->mContext.mSubscriptionObj->unsubscribe( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + std::move(dataItemsToUnsubscribe)), + mParent); + } + } + } + SystemStatusOsObserver* mParent; + IDataItemObserver* mClient; + unordered_set<DataItemId> mDataItemSet; + }; + + if (l.empty() || nullptr == client) { + LOC_LOGw("Data item set is empty or client is nullptr"); + } else { + mContext.mMsgTask->sendMsg( + new HandleUpdateSubscriptionReq(this, (list<DataItemId>&)l, client)); + } +} + +void SystemStatusOsObserver::unsubscribe( + const list<DataItemId>& l, IDataItemObserver* client) +{ + struct HandleUnsubscribeReq : public LocMsg { + HandleUnsubscribeReq(SystemStatusOsObserver* parent, + list<DataItemId>& l, IDataItemObserver* client) : + mParent(parent), mClient(client), + mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {} + + void proc() const { + unordered_set<DataItemId> dataItemsUnusedByClient = {}; + unordered_set<IDataItemObserver*> clientToRemove = {}; + unordered_set<DataItemId> dataItemsToUnsubscribe = {}; + mParent->mClientToDataItems.trimOrRemove({mClient}, mDataItemSet, &clientToRemove, + &dataItemsUnusedByClient); + mParent->mDataItemToClients.trimOrRemove(dataItemsUnusedByClient, {mClient}, + &dataItemsToUnsubscribe, nullptr); + + if (nullptr != mParent->mContext.mSubscriptionObj && !dataItemsToUnsubscribe.empty()) { + LOC_LOGD("Unsubscribe Request sent to framework for the following data items"); + mParent->logMe(dataItemsToUnsubscribe); + + // Send unsubscribe to framework + mParent->mContext.mSubscriptionObj->unsubscribe( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + std::move(dataItemsToUnsubscribe)), + mParent); + } + } + SystemStatusOsObserver* mParent; + IDataItemObserver* mClient; + unordered_set<DataItemId> mDataItemSet; + }; + + if (l.empty() || nullptr == client) { + LOC_LOGw("Data item set is empty or client is nullptr"); + } else { + mContext.mMsgTask->sendMsg(new HandleUnsubscribeReq(this, (list<DataItemId>&)l, client)); + } +} + +void SystemStatusOsObserver::unsubscribeAll(IDataItemObserver* client) +{ + struct HandleUnsubscribeAllReq : public LocMsg { + HandleUnsubscribeAllReq(SystemStatusOsObserver* parent, + IDataItemObserver* client) : + mParent(parent), mClient(client) {} + + void proc() const { + unordered_set<DataItemId> diByClient = mParent->mClientToDataItems.getValSet(mClient); + + if (!diByClient.empty()) { + unordered_set<DataItemId> dataItemsToUnsubscribe; + mParent->mClientToDataItems.remove(mClient); + mParent->mDataItemToClients.trimOrRemove(diByClient, {mClient}, + &dataItemsToUnsubscribe, nullptr); + + if (!dataItemsToUnsubscribe.empty() && + nullptr != mParent->mContext.mSubscriptionObj) { + + LOC_LOGD("Unsubscribe Request sent to framework for the following data items"); + mParent->logMe(dataItemsToUnsubscribe); + + // Send unsubscribe to framework + mParent->mContext.mSubscriptionObj->unsubscribe( + containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( + std::move(dataItemsToUnsubscribe)), + mParent); + } + } + } + SystemStatusOsObserver* mParent; + IDataItemObserver* mClient; + }; + + if (nullptr == client) { + LOC_LOGw("Data item set is empty or client is nullptr"); + } else { + mContext.mMsgTask->sendMsg(new HandleUnsubscribeAllReq(this, client)); + } +} + +/****************************************************************************** + IDataItemObserver Overrides +******************************************************************************/ +void SystemStatusOsObserver::notify(const list<IDataItemCore*>& dlist) +{ + struct HandleNotify : public LocMsg { + HandleNotify(SystemStatusOsObserver* parent, vector<IDataItemCore*>& v) : + mParent(parent), mDiVec(std::move(v)) {} + + inline virtual ~HandleNotify() { + for (auto item : mDiVec) { + delete item; + } + } + + void proc() const { + // Update Cache with received data items and prepare + // list of data items to be sent. + unordered_set<DataItemId> dataItemIdsToBeSent = {}; + for (auto item : mDiVec) { + if (mParent->updateCache(item)) { + dataItemIdsToBeSent.insert(item->getId()); + } + } + + // Send data item to all subscribed clients + unordered_set<IDataItemObserver*> clientSet = {}; + for (auto each : dataItemIdsToBeSent) { + auto clients = mParent->mDataItemToClients.getValSetPtr(each); + if (nullptr != clients) { + clientSet.insert(clients->begin(), clients->end()); + } + } + + for (auto client : clientSet) { + unordered_set<DataItemId> dataItemIdsForThisClient( + mParent->mClientToDataItems.getValSet(client)); + for (auto itr = dataItemIdsForThisClient.begin(); + itr != dataItemIdsForThisClient.end(); ) { + if (dataItemIdsToBeSent.find(*itr) == dataItemIdsToBeSent.end()) { + itr = dataItemIdsForThisClient.erase(itr); + } else { + itr++; + } + } + + mParent->sendCachedDataItems(dataItemIdsForThisClient, client); + } + } + SystemStatusOsObserver* mParent; + const vector<IDataItemCore*> mDiVec; + }; + + if (!dlist.empty()) { + vector<IDataItemCore*> dataItemVec(dlist.size()); + + for (auto each : dlist) { + + IDataItemCore* di = DataItemsFactoryProxy::createNewDataItem(each->getId()); + if (nullptr == di) { + LOC_LOGw("Unable to create dataitem:%d", each->getId()); + continue; + } + + // Copy contents into the newly created data item + di->copy(each); + + // add this dataitem if updated from last one + dataItemVec.push_back(di); + IF_LOC_LOGD { + string dv; + di->stringify(dv); + LOC_LOGd("notify: DataItem In Value:%s", dv.c_str()); + } + } + + if (!dataItemVec.empty()) { + mContext.mMsgTask->sendMsg(new HandleNotify(this, dataItemVec)); + } + } +} + +/****************************************************************************** + IFrameworkActionReq Overrides +******************************************************************************/ +void SystemStatusOsObserver::turnOn(DataItemId dit, int timeOut) +{ + if (nullptr == mContext.mFrameworkActionReqObj) { + LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__); + return; + } + + // Check if data item exists in mActiveRequestCount + DataItemIdToInt::iterator citer = mActiveRequestCount.find(dit); + if (citer == mActiveRequestCount.end()) { + // Data item not found in map + // Add reference count as 1 and add dataitem to map + pair<DataItemId, int> cpair(dit, 1); + mActiveRequestCount.insert(cpair); + LOC_LOGD("Sending turnOn request"); + + // Send action turn on to framework + struct HandleTurnOnMsg : public LocMsg { + HandleTurnOnMsg(IFrameworkActionReq* framework, + DataItemId dit, int timeOut) : + mFrameworkActionReqObj(framework), mDataItemId(dit), mTimeOut(timeOut) {} + virtual ~HandleTurnOnMsg() {} + void proc() const { + mFrameworkActionReqObj->turnOn(mDataItemId, mTimeOut); + } + IFrameworkActionReq* mFrameworkActionReqObj; + DataItemId mDataItemId; + int mTimeOut; + }; + mContext.mMsgTask->sendMsg( + new (nothrow) HandleTurnOnMsg(mContext.mFrameworkActionReqObj, dit, timeOut)); + } + else { + // Found in map, update reference count + citer->second++; + LOC_LOGD("turnOn - Data item:%d Num_refs:%d", dit, citer->second); + } +} + +void SystemStatusOsObserver::turnOff(DataItemId dit) +{ + if (nullptr == mContext.mFrameworkActionReqObj) { + LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__); + return; + } + + // Check if data item exists in mActiveRequestCount + DataItemIdToInt::iterator citer = mActiveRequestCount.find(dit); + if (citer != mActiveRequestCount.end()) { + // found + citer->second--; + LOC_LOGD("turnOff - Data item:%d Remaining:%d", dit, citer->second); + if(citer->second == 0) { + // if this was last reference, remove item from map and turn off module + mActiveRequestCount.erase(citer); + + // Send action turn off to framework + struct HandleTurnOffMsg : public LocMsg { + HandleTurnOffMsg(IFrameworkActionReq* framework, DataItemId dit) : + mFrameworkActionReqObj(framework), mDataItemId(dit) {} + virtual ~HandleTurnOffMsg() {} + void proc() const { + mFrameworkActionReqObj->turnOff(mDataItemId); + } + IFrameworkActionReq* mFrameworkActionReqObj; + DataItemId mDataItemId; + }; + mContext.mMsgTask->sendMsg( + new (nothrow) HandleTurnOffMsg(mContext.mFrameworkActionReqObj, dit)); + } + } +} + +#ifdef USE_GLIB +bool SystemStatusOsObserver::connectBackhaul(const string& clientName) +{ + bool result = false; + + if (mContext.mFrameworkActionReqObj != NULL) { + struct HandleConnectBackhaul : public LocMsg { + HandleConnectBackhaul(IFrameworkActionReq* fwkActReq, const string& clientName) : + mClientName(clientName), mFwkActionReqObj(fwkActReq) {} + virtual ~HandleConnectBackhaul() {} + void proc() const { + LOC_LOGi("HandleConnectBackhaul::enter"); + mFwkActionReqObj->connectBackhaul(mClientName); + LOC_LOGi("HandleConnectBackhaul::exit"); + } + IFrameworkActionReq* mFwkActionReqObj; + string mClientName; + }; + mContext.mMsgTask->sendMsg( + new (nothrow) HandleConnectBackhaul(mContext.mFrameworkActionReqObj, clientName)); + result = true; + } + else { + LOC_LOGe("Framework action request object is NULL.Caching connect request: %s", + clientName.c_str()); + ClientBackhaulReqCache::const_iterator iter = mBackHaulConnReqCache.find(clientName); + if (iter == mBackHaulConnReqCache.end()) { + // not found in set. first time receiving from request from client + LOC_LOGe("Adding client to BackHaulConnReqCache list"); + mBackHaulConnReqCache.insert(clientName); + } + result = false; + } + return result; + +} + +bool SystemStatusOsObserver::disconnectBackhaul(const string& clientName) +{ + bool result = false; + + if (mContext.mFrameworkActionReqObj != NULL) { + struct HandleDisconnectBackhaul : public LocMsg { + HandleDisconnectBackhaul(IFrameworkActionReq* fwkActReq, const string& clientName) : + mClientName(clientName), mFwkActionReqObj(fwkActReq) {} + virtual ~HandleDisconnectBackhaul() {} + void proc() const { + LOC_LOGi("HandleDisconnectBackhaul::enter"); + mFwkActionReqObj->disconnectBackhaul(mClientName); + LOC_LOGi("HandleDisconnectBackhaul::exit"); + } + IFrameworkActionReq* mFwkActionReqObj; + string mClientName; + }; + mContext.mMsgTask->sendMsg( + new (nothrow) HandleDisconnectBackhaul(mContext.mFrameworkActionReqObj, + clientName)); + } + else { + LOC_LOGe("Framework action request object is NULL.Caching disconnect request: %s", + clientName.c_str()); + // Check if client has requested for backhaul connection. + ClientBackhaulReqCache::const_iterator iter = mBackHaulConnReqCache.find(clientName); + if (iter != mBackHaulConnReqCache.end()) { + // client found, remove from set. + LOC_LOGd("Removing client from BackHaulConnReqCache list"); + mBackHaulConnReqCache.erase(iter); + } + result = false; + } + return result; +} +#endif +/****************************************************************************** + Helpers +******************************************************************************/ +void SystemStatusOsObserver::sendCachedDataItems( + const unordered_set<DataItemId>& s, IDataItemObserver* to) +{ + if (nullptr == to) { + LOC_LOGv("client pointer is NULL."); + } else { + string clientName; + to->getName(clientName); + list<IDataItemCore*> dataItems = {}; + + for (auto each : s) { + auto citer = mDataItemCache.find(each); + if (citer != mDataItemCache.end()) { + string dv; + citer->second->stringify(dv); + LOC_LOGI("DataItem: %s >> %s", dv.c_str(), clientName.c_str()); + dataItems.push_front(citer->second); + } + } + + if (dataItems.empty()) { + LOC_LOGv("No items to notify."); + } else { + to->notify(dataItems); + } + } +} + +bool SystemStatusOsObserver::updateCache(IDataItemCore* d) +{ + bool dataItemUpdated = false; + + // Request systemstatus to record this dataitem in its cache + // if the return is false, it means that SystemStatus is not + // handling it, so SystemStatusOsObserver also doesn't. + // So it has to be true to proceed. + if (nullptr != d && mSystemStatus->eventDataItemNotify(d)) { + auto citer = mDataItemCache.find(d->getId()); + if (citer == mDataItemCache.end()) { + // New data item; not found in cache + IDataItemCore* dataitem = DataItemsFactoryProxy::createNewDataItem(d->getId()); + if (nullptr != dataitem) { + // Copy the contents of the data item + dataitem->copy(d); + // Insert in mDataItemCache + mDataItemCache.insert(std::make_pair(d->getId(), dataitem)); + dataItemUpdated = true; + } + } else { + // Found in cache; Update cache if necessary + citer->second->copy(d, &dataItemUpdated); + } + + if (dataItemUpdated) { + LOC_LOGV("DataItem:%d updated:%d", d->getId(), dataItemUpdated); + } + } + + return dataItemUpdated; +} + +} // namespace loc_core + |