diff options
Diffstat (limited to 'gps/core/SystemStatusOsObserver.cpp')
-rw-r--r-- | gps/core/SystemStatusOsObserver.cpp | 646 |
1 files changed, 646 insertions, 0 deletions
diff --git a/gps/core/SystemStatusOsObserver.cpp b/gps/core/SystemStatusOsObserver.cpp new file mode 100644 index 0000000..e327f93 --- /dev/null +++ b/gps/core/SystemStatusOsObserver.cpp @@ -0,0 +1,646 @@ +/* Copyright (c) 2015-2017, 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 <string> +#include <cinttypes> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <pthread.h> +#include <iterator> +#include <algorithm> + +#include <MsgTask.h> +#include <SystemStatusOsObserver.h> + +#include <DataItemId.h> +#include <IDataItemCore.h> +#include <IClientIndex.h> +#include <IDataItemIndex.h> +#include <IndexFactory.h> + +#include <DataItemsFactoryProxy.h> + +#include <platform_lib_log_util.h> + +namespace loc_core +{ +#define BREAK_IF_ZERO(ERR,X) if(0==(X)) {result = (ERR); break;} +#define BREAK_IF_NON_ZERO(ERR,X) if(0!=(X)) {result = (ERR); break;} + +SystemStatusOsObserver::SystemStatusOsObserver(const MsgTask* msgTask) : + mAddress ("SystemStatusOsObserver"), + mClientIndex(IndexFactory <IDataItemObserver *, DataItemId> :: createClientIndex ()), + mDataItemIndex(IndexFactory <IDataItemObserver *, DataItemId> :: createDataItemIndex ()) +{ + int result = -1; + ENTRY_LOG (); + do { + BREAK_IF_ZERO (1, mClientIndex); + BREAK_IF_ZERO (2, mDataItemIndex); + mContext.mMsgTask = msgTask; + result = 0; + } while (0); + EXIT_LOG_WITH_ERROR ("%d",result); +} + +SystemStatusOsObserver :: ~SystemStatusOsObserver () +{ + // Close data-item library handle + DataItemsFactoryProxy::closeDataItemLibraryHandle(); + + // Destroy cache + map <DataItemId, IDataItemCore *> :: iterator citer = mDataItemCache.begin (); + for (; citer != mDataItemCache.end (); ++citer) { + if (citer->second != NULL) { delete citer->second; } + } + mDataItemCache.clear (); + delete mClientIndex; + delete mDataItemIndex; + mClientIndex = NULL; + mDataItemIndex = NULL; +} + +/****************************************************************************** + Message proc +******************************************************************************/ +void SystemStatusOsObserver :: HandleSubscribeReq :: proc () const { + + int result = 0; + ENTRY_LOG (); + do { + if (mDataItemList.empty ()) { + LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); + result = 0; + break; + } + //mDataItemList.sort (); + // Handle First Response + list <DataItemId> pendingFirstResponseList; + this->mParent->mClientIndex->add (this->mClient, mDataItemList, pendingFirstResponseList); + + // Do not send first response for only pendingFirstResponseList, + // instead send for all the data items (present in the cache) that + // have been subscribed for each time. + this->mParent->sendFirstResponse (mDataItemList, this->mClient); + + list <DataItemId> yetToSubscribeDataItemsList; + this->mParent->mDataItemIndex->add (this->mClient, mDataItemList, yetToSubscribeDataItemsList); + // Send subscription list to framework + if (!yetToSubscribeDataItemsList.empty ()) { + this->mParent->mContext.mSubscriptionObj->subscribe + ( + yetToSubscribeDataItemsList, + this->mParent + ); + LOC_LOGD ("Subscribe Request sent to framework for the following data items"); + this->mParent->logMe (yetToSubscribeDataItemsList); + } + + } while (0); + EXIT_LOG_WITH_ERROR ("%d", result); + return; +} + +void SystemStatusOsObserver :: HandleUpdateSubscriptionReq :: proc () const { + int result = 0; + ENTRY_LOG (); + do { + if (mDataItemList.empty ()) { + LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); + result = 0; + break; + } + //mDataItemList.sort (); + list <DataItemId> currentlySubscribedList; + this->mParent->mClientIndex->getSubscribedList (this->mClient, currentlySubscribedList); + list <DataItemId> removeDataItemList; + set_difference (currentlySubscribedList.begin (), currentlySubscribedList.end (), + mDataItemList.begin (), mDataItemList.end (), + inserter (removeDataItemList,removeDataItemList.begin ())); + // Handle First Response + list <DataItemId> pendingFirstResponseList; + this->mParent->mClientIndex->add (this->mClient, mDataItemList, pendingFirstResponseList); + // Send First Response + this->mParent->sendFirstResponse (pendingFirstResponseList, this->mClient); + + list <DataItemId> yetToSubscribeDataItemsList; + this->mParent->mDataItemIndex->add (this->mClient, mDataItemList, yetToSubscribeDataItemsList); + // Send subscription list to framework + if (!yetToSubscribeDataItemsList.empty ()) { + this->mParent->mContext.mSubscriptionObj->subscribe + ( + yetToSubscribeDataItemsList, + this->mParent + ); + LOC_LOGD ("Subscribe Request sent to framework for the following data items"); + this->mParent->logMe (yetToSubscribeDataItemsList); + } + + list <DataItemId> unsubscribeList; + list <DataItemId> unused; + this->mParent->mClientIndex->remove (this->mClient, removeDataItemList, unused); + + if (!this->mParent->mClientIndex->isSubscribedClient (this->mClient)) { + this->mParent->mDataItemIndex->remove (list <IDataItemObserver *> (1,this->mClient), unsubscribeList); + } + if (!unsubscribeList.empty ()) { + // Send unsubscribe to framework + this->mParent->mContext.mSubscriptionObj->unsubscribe + ( + unsubscribeList, + this->mParent + ); + LOC_LOGD ("Unsubscribe Request sent to framework for the following data items"); + this->mParent->logMe (unsubscribeList); + } + } while (0); + EXIT_LOG_WITH_ERROR ("%d",result); +} + +void SystemStatusOsObserver :: HandleRequestData :: proc () const { + int result = 0; + ENTRY_LOG (); + + do { + if (mDataItemList.empty ()) { + LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); + result = 0; + break; + } + //mDataItemList.sort (); + list <DataItemId> yetToSubscribeDataItemsList; + this->mParent->mClientIndex->add (this->mClient, mDataItemList, yetToSubscribeDataItemsList); + this->mParent->mDataItemIndex->add (this->mClient, mDataItemList, yetToSubscribeDataItemsList); + // Send subscription list to framework + if (!mDataItemList.empty ()) { + this->mParent->mContext.mSubscriptionObj->requestData + ( + mDataItemList, + this->mParent + ); + LOC_LOGD ("Subscribe Request sent to framework for the following data items"); + this->mParent->logMe (yetToSubscribeDataItemsList); + } + + } while (0); + EXIT_LOG_WITH_ERROR ("%d",result); +} + +void SystemStatusOsObserver :: HandleUnsubscribeReq :: proc () const { + int result = 0; + ENTRY_LOG (); + do { + if (mDataItemList.empty ()) { + LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); + result = 0; + break; + } + //mDataItemList.sort (); + list <DataItemId> unsubscribeList; + list <DataItemId> unused; + this->mParent->mClientIndex->remove (this->mClient, mDataItemList, unused); + + list <DataItemId> :: const_iterator it = mDataItemList.begin (); + for (; it != mDataItemList.end (); ++it) { + list <IDataItemObserver *> clientListSubs; + list <IDataItemObserver *> clientListOut; + this->mParent->mDataItemIndex->remove ((*it), + list <IDataItemObserver *> (1,this->mClient), clientListOut); + // check if there are any other subscribed client for this data item id + this->mParent->mDataItemIndex->getListOfSubscribedClients ( (*it), clientListSubs); + if (clientListSubs.empty()) + { + LOC_LOGD ("Client list subscribed is empty for dataitem - %d",(*it)); + unsubscribeList.push_back((*it)); + } + } + if (!unsubscribeList.empty ()) { + // Send unsubscribe to framework + this->mParent->mContext.mSubscriptionObj->unsubscribe + ( + unsubscribeList, + this->mParent + ); + LOC_LOGD ("Unsubscribe Request sent to framework for the following data items"); + this->mParent->logMe (unsubscribeList); + } + } while (0); + EXIT_LOG_WITH_ERROR ("%d",result); +} + +void SystemStatusOsObserver :: HandleUnsubscribeAllReq :: proc () const { + int result = 0; + ENTRY_LOG (); + do { + list <IDataItemObserver *> clients (1, this->mClient); + list <DataItemId> unsubscribeList; + BREAK_IF_NON_ZERO (2, this->mParent->mClientIndex->remove (this->mClient)); + + + this->mParent->mDataItemIndex->remove (clients, unsubscribeList); + if (!unsubscribeList.empty ()) { + // Send unsubscribe to framework + this->mParent->mContext.mSubscriptionObj->unsubscribe + ( + unsubscribeList, + this->mParent + ); + LOC_LOGD ("Unsubscribe Request sent to framework for the following data items"); + this->mParent->logMe (unsubscribeList); + } + } while (0); + EXIT_LOG_WITH_ERROR ("%d",result); +} + +void SystemStatusOsObserver :: HandleNotify :: getListOfClients + (const list <DataItemId> & dlist, list <IDataItemObserver *> & clients ) const { + + list <DataItemId> :: const_iterator it = dlist.begin (); + for (; it != dlist.end (); ++it) { + list <IDataItemObserver *> clientList; + this->mParent->mDataItemIndex->getListOfSubscribedClients ( (*it), clientList); + list <IDataItemObserver *> :: iterator citer = clientList.begin (); + for (; citer != clientList.end (); ++citer) { + clients.push_back (*citer); + } + clientList.clear (); + } + // remove duplicates + clients.unique (); +} + +void SystemStatusOsObserver :: HandleNotify :: proc () const { + int result = 0; + ENTRY_LOG (); + do { + // Update Cache with received data items and prepare + // list of data items to be sent. + list <IDataItemCore *> :: const_iterator it = mDList.begin (); + list <DataItemId> dataItemIdsToBeSent; + for (; it != mDList.end (); ++it) { + bool dataItemUpdated = false; + this->mParent->updateCache (*it, dataItemUpdated); + if (dataItemUpdated) { + dataItemIdsToBeSent.push_back ( (*it)->getId ()); + } + } + + list <IDataItemObserver *> clientList; + this->getListOfClients (dataItemIdsToBeSent, clientList); + list <IDataItemObserver *> :: iterator citer = clientList.begin (); + // Send data item to all subscribed clients + LOC_LOGD ("LocTech-Label :: SystemStatusOsObserver :: Data Items Out"); + for (; citer != clientList.end (); ++citer) { + do { + list <DataItemId> dataItemIdsSubscribedByThisClient; + list <DataItemId> dataItemIdsToBeSentForThisClient; + this->mParent->mClientIndex->getSubscribedList (*citer, dataItemIdsSubscribedByThisClient); + dataItemIdsSubscribedByThisClient.sort (); + dataItemIdsToBeSent.sort (); + set_intersection (dataItemIdsToBeSent.begin (), + dataItemIdsToBeSent.end (), + dataItemIdsSubscribedByThisClient.begin (), + dataItemIdsSubscribedByThisClient.end (), + inserter (dataItemIdsToBeSentForThisClient, + dataItemIdsToBeSentForThisClient.begin ())); + BREAK_IF_NON_ZERO (4,this->mParent->sendCachedDataItems (dataItemIdsToBeSentForThisClient, *citer)); + dataItemIdsSubscribedByThisClient.clear (); + dataItemIdsToBeSentForThisClient.clear (); + } while (0); + } + } while (0); + EXIT_LOG_WITH_ERROR ("%d", result); +} + +void SystemStatusOsObserver :: HandleTurnOn :: proc () const { + int result = 0; + ENTRY_LOG (); + do { + // Send action turn on to framework + this->mParent->mContext.mFrameworkActionReqObj->turnOn(mDataItemId, mTimeOut); + } while (0); + EXIT_LOG_WITH_ERROR ("%d", result); +} + +void SystemStatusOsObserver :: HandleTurnOff :: proc () const { + int result = 0; + ENTRY_LOG (); + do { + // Send action turn off to framework + this->mParent->mContext.mFrameworkActionReqObj->turnOff(mDataItemId); + } while (0); + EXIT_LOG_WITH_ERROR ("%d", result); +} + +/****************************************************************************** + IDataItemSubscription Overrides +******************************************************************************/ +void SystemStatusOsObserver :: subscribe (const list <DataItemId> & l, IDataItemObserver * client) { + int result = 0; + ENTRY_LOG (); + do { + if (mContext.mSubscriptionObj != NULL) { + HandleSubscribeReq * msg = new (nothrow) HandleSubscribeReq (this, l, client); + mContext.mMsgTask->sendMsg (msg); + } + else { + LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__); + result = 1; + } + } while (0); + EXIT_LOG_WITH_ERROR ("%d",result); +} + +void SystemStatusOsObserver :: updateSubscription (const list <DataItemId> & l, IDataItemObserver * client) { + int result = 0; + ENTRY_LOG (); + do { + if (mContext.mSubscriptionObj != NULL) { + mContext.mMsgTask->sendMsg (new (nothrow) HandleUpdateSubscriptionReq (this, l, client)); + } + else { + LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__); + result = 1; + } + } while (0); + EXIT_LOG_WITH_ERROR ("%d",result); +} + +void SystemStatusOsObserver :: requestData (const list <DataItemId> & l, IDataItemObserver * client) { + int result = 0; + ENTRY_LOG (); + do { + if (mContext.mSubscriptionObj != NULL) { + mContext.mMsgTask->sendMsg (new (nothrow) HandleRequestData (this, l, client)); + } + else { + LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__); + result = 1; + } + } while (0); + + EXIT_LOG_WITH_ERROR ("%d",result); +} + +void SystemStatusOsObserver :: unsubscribe (const list <DataItemId> & l, IDataItemObserver * client) { + int result = 0; + ENTRY_LOG (); + do { + if (mContext.mSubscriptionObj != NULL) { + mContext.mMsgTask->sendMsg (new (nothrow) HandleUnsubscribeReq (this, l, client)); + } + else { + LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__); + result = 1; + } + } while (0); + EXIT_LOG_WITH_ERROR ("%d",result); +} + +void SystemStatusOsObserver :: unsubscribeAll (IDataItemObserver * client) { + int result = 0; + ENTRY_LOG (); + do { + if (mContext.mSubscriptionObj != NULL) { + mContext.mMsgTask->sendMsg (new (nothrow) HandleUnsubscribeAllReq (this, client)); + } + else { + LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__); + result = 1; + } + } while (0); + EXIT_LOG_WITH_ERROR ("%d",result); +} + +/****************************************************************************** + IDataItemObserver Overrides +******************************************************************************/ +void SystemStatusOsObserver::getName(string & name) { + name = mAddress; +} + +void SystemStatusOsObserver::notify(const std::list <IDataItemCore *> & dlist) { + int result = 0; + ENTRY_LOG (); + do { + list <IDataItemCore *> :: const_iterator it = dlist.begin (); + list <IDataItemCore *> dataItemList; + list <DataItemId> ids; + LOC_LOGD("LocTech-Label :: SystemStatusOsObserver :: Data Items In"); + for (; it != dlist.end (); ++it) { + if (*it != NULL) { + string dv; + (*it)->stringify(dv); + LOC_LOGD("LocTech-Value :: Data Item Value: %s", dv.c_str ()); + IDataItemCore * dataitem = DataItemsFactoryProxy::createNewDataItem((*it)->getId()); + BREAK_IF_ZERO (2, dataitem); + // Copy contents into the newly created data item + dataitem->copy(*it); + dataItemList.push_back(dataitem); + ids.push_back((*it)->getId()); + } + } + mContext.mMsgTask->sendMsg(new (nothrow) HandleNotify (this, dataItemList)); + } while (0); + EXIT_LOG_WITH_ERROR ("%d", result); +} + +/****************************************************************************** + IFrameworkActionReq Overrides +******************************************************************************/ +void SystemStatusOsObserver :: turnOn (DataItemId dit, int timeOut) { + int result = 0; + ENTRY_LOG (); + do { + if (mContext.mFrameworkActionReqObj != NULL) { + // Check if data item exists in mActiveRequestCount + map <DataItemId, int> :: 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 + mContext.mMsgTask->sendMsg (new (nothrow) HandleTurnOn (this, dit, timeOut)); + } else { + // Found in map, update reference count + citer->second++; + LOC_LOGD("HandleTurnOn - Data item:%d Num_refs:%d",dit,citer->second); + } + } + else { + LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__); + result = 1; + } + } while (0); + + EXIT_LOG_WITH_ERROR ("%d", result); +} + +void SystemStatusOsObserver :: turnOff (DataItemId dit) { + int result = 0; + ENTRY_LOG (); + do { + if (mContext.mFrameworkActionReqObj != NULL) { + // Check if data item exists in mActiveRequestCount + map <DataItemId, int> :: iterator citer = mActiveRequestCount.find (dit); + if (citer != mActiveRequestCount.end ()) { + citer->second--; + LOC_LOGD("HandleTurnOff - Data item:%d Remaining Num_refs:%d",dit,citer->second); + + if(citer->second == 0) { + LOC_LOGD("Sending turnOff request"); + // if this was last reference, remove item from map and turn off module + mActiveRequestCount.erase(citer); + // Send action turn off to framework + mContext.mMsgTask->sendMsg (new (nothrow) HandleTurnOff (this, dit)); + } + } else { + // Not found in map + LOC_LOGD ("Data item id %d not found in FrameworkModuleMap",dit); + } + } + else { + LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__); + result = 1; + } + } while (0); + EXIT_LOG_WITH_ERROR ("%d", result); +} + +/****************************************************************************** + Helpers +******************************************************************************/ +void SystemStatusOsObserver :: logMe (const list <DataItemId> & l) { + list <DataItemId> :: const_iterator it = l.begin (); + for (;it != l.end (); ++it) { + LOC_LOGD ("DataItem %d",*it); + } +} + +int SystemStatusOsObserver :: sendFirstResponse (const list <DataItemId> & l, IDataItemObserver * to) { + int result = 0; + ENTRY_LOG (); + do { + if (l.empty ()) { + LOC_LOGV("list is empty. Nothing to do. Exiting"); + result = 0; + break; + } + + string clientName; + to->getName (clientName); + LOC_LOGD ("First response sent for the following data items To Client: %s", clientName.c_str()); + + list <IDataItemCore *> dataItems; + list <DataItemId> :: const_iterator diditer = l.begin (); + for (; diditer != l.end (); ++diditer) { + map <DataItemId, IDataItemCore*> :: const_iterator citer = mDataItemCache.find (*diditer); + if (citer != mDataItemCache.end ()) { + string dv; + IDataItemCore * di = citer->second; + di->stringify (dv); + LOC_LOGD ("LocTech-Value :: Data Item: %s", dv.c_str ()); + dataItems.push_back (citer->second); + } + } + if (dataItems.empty ()) { + LOC_LOGV("No items to notify. Nothing to do. Exiting"); + result = 0; + break; + } + + // Notify Client + to->notify (dataItems); + + } while (0); + EXIT_LOG_WITH_ERROR ("%d", result); + return result; +} + +int SystemStatusOsObserver :: sendCachedDataItems (const list <DataItemId> & l, IDataItemObserver * to) { + int result = 0; + ENTRY_LOG (); + do { + list <IDataItemCore *> dataItems; + list <DataItemId> :: const_iterator it = l.begin (); + string clientName; + to->getName (clientName); + LOC_LOGD ("LocTech-Value :: To Client: %s", clientName.c_str ()); + for (; it != l.end (); ++it) { + string dv; + IDataItemCore * di = this->mDataItemCache [ (*it) ]; + di->stringify (dv); + LOC_LOGI("LocTech-Value :: Data Item: %s >> %s", dv.c_str(), clientName.c_str()); + dataItems.push_back (di); + } + + to->notify (dataItems); + + } while (0); + EXIT_LOG_WITH_ERROR ("%d", result); + return result; +} + +int SystemStatusOsObserver :: updateCache (IDataItemCore * d, bool &dataItemUpdated) { + int result = 0; + ENTRY_LOG (); + do { + BREAK_IF_ZERO (1, d); + // Check if data item exists in cache + map <DataItemId, IDataItemCore*> :: iterator citer = mDataItemCache.find (d->getId ()); + if (citer == mDataItemCache.end ()) { + // New data item; not found in cache + IDataItemCore * dataitem = DataItemsFactoryProxy::createNewDataItem(d->getId()); + BREAK_IF_ZERO (2, dataitem); + // Copy the contents of the data item + dataitem->copy (d); + pair <DataItemId, IDataItemCore*> cpair (d->getId (), dataitem); + // Insert in mDataItemCache + mDataItemCache.insert (cpair); + dataItemUpdated = true; + } else { + // Found in cache; Update cache if necessary + BREAK_IF_NON_ZERO(3, citer->second->copy (d, &dataItemUpdated)); + } + + if (dataItemUpdated) { + LOC_LOGV("DataItem:%d updated:%d", d->getId (), dataItemUpdated); + } + } while (0); + + EXIT_LOG_WITH_ERROR ("%d", result); + return result; +} + +} // namespace loc_core + |