/* 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 :: createClientIndex ()), mDataItemIndex(IndexFactory :: 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 :: 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 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 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 currentlySubscribedList; this->mParent->mClientIndex->getSubscribedList (this->mClient, currentlySubscribedList); list removeDataItemList; set_difference (currentlySubscribedList.begin (), currentlySubscribedList.end (), mDataItemList.begin (), mDataItemList.end (), inserter (removeDataItemList,removeDataItemList.begin ())); // Handle First Response list pendingFirstResponseList; this->mParent->mClientIndex->add (this->mClient, mDataItemList, pendingFirstResponseList); // Send First Response this->mParent->sendFirstResponse (pendingFirstResponseList, this->mClient); list 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 unsubscribeList; list unused; this->mParent->mClientIndex->remove (this->mClient, removeDataItemList, unused); if (!this->mParent->mClientIndex->isSubscribedClient (this->mClient)) { this->mParent->mDataItemIndex->remove (list (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 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 unsubscribeList; list unused; this->mParent->mClientIndex->remove (this->mClient, mDataItemList, unused); list :: const_iterator it = mDataItemList.begin (); for (; it != mDataItemList.end (); ++it) { list clientListSubs; list clientListOut; this->mParent->mDataItemIndex->remove ((*it), list (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 clients (1, this->mClient); list 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 & dlist, list & clients ) const { list :: const_iterator it = dlist.begin (); for (; it != dlist.end (); ++it) { list clientList; this->mParent->mDataItemIndex->getListOfSubscribedClients ( (*it), clientList); list :: 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 :: const_iterator it = mDList.begin (); list dataItemIdsToBeSent; for (; it != mDList.end (); ++it) { bool dataItemUpdated = false; this->mParent->updateCache (*it, dataItemUpdated); if (dataItemUpdated) { dataItemIdsToBeSent.push_back ( (*it)->getId ()); } } list clientList; this->getListOfClients (dataItemIdsToBeSent, clientList); list :: 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 dataItemIdsSubscribedByThisClient; list 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 & 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 & 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 & 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 & 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 & dlist) { int result = 0; ENTRY_LOG (); do { list :: const_iterator it = dlist.begin (); list dataItemList; list 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 :: 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 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 :: 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 & l) { list :: const_iterator it = l.begin (); for (;it != l.end (); ++it) { LOC_LOGD ("DataItem %d",*it); } } int SystemStatusOsObserver :: sendFirstResponse (const list & 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 dataItems; list :: const_iterator diditer = l.begin (); for (; diditer != l.end (); ++diditer) { map :: 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 & l, IDataItemObserver * to) { int result = 0; ENTRY_LOG (); do { list dataItems; list :: 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 :: 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 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