1 /* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. 2 * 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions are 5 * met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer in the documentation and/or other materials provided 11 * with the distribution. 12 * * Neither the name of The Linux Foundation, nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 #define LOG_TAG "LocSvc_SystemStatusOsObserver" 30 31 #include <algorithm> 32 #include <SystemStatus.h> 33 #include <SystemStatusOsObserver.h> 34 #include <IDataItemCore.h> 35 #include <IClientIndex.h> 36 #include <IDataItemIndex.h> 37 #include <IndexFactory.h> 38 #include <DataItemsFactoryProxy.h> 39 40 namespace loc_core 41 { 42 SystemStatusOsObserver::SystemStatusOsObserver(const MsgTask* msgTask) : 43 mAddress("SystemStatusOsObserver"), 44 mClientIndex(IndexFactory<IDataItemObserver*, DataItemId> :: createClientIndex()), 45 mDataItemIndex(IndexFactory<IDataItemObserver*, DataItemId> :: createDataItemIndex()) 46 { 47 mContext.mMsgTask = msgTask; 48 } 49 50 SystemStatusOsObserver::~SystemStatusOsObserver() 51 { 52 // Close data-item library handle 53 DataItemsFactoryProxy::closeDataItemLibraryHandle(); 54 55 // Destroy cache 56 for (auto each : mDataItemCache) { 57 if (nullptr != each.second) { 58 delete each.second; 59 } 60 } 61 62 mDataItemCache.clear(); 63 delete mClientIndex; 64 delete mDataItemIndex; 65 } 66 67 void SystemStatusOsObserver::setSubscriptionObj(IDataItemSubscription* subscriptionObj) 68 { 69 mContext.mSubscriptionObj = subscriptionObj; 70 71 LOC_LOGD("Request cache size - Subscribe:%zu RequestData:%zu", 72 mSubscribeReqCache.size(), mReqDataCache.size()); 73 74 // we have received the subscription object. process cached requests 75 // process - subscribe request cache 76 for (auto each : mSubscribeReqCache) { 77 subscribe(each.second, each.first); 78 } 79 // process - requestData request cache 80 for (auto each : mReqDataCache) { 81 requestData(each.second, each.first); 82 } 83 } 84 85 // Helper to cache requests subscribe and requestData till subscription obj is obtained 86 void SystemStatusOsObserver::cacheObserverRequest(ObserverReqCache& reqCache, 87 const list<DataItemId>& l, IDataItemObserver* client) 88 { 89 ObserverReqCache::iterator dicIter = reqCache.find(client); 90 if (dicIter != reqCache.end()) { 91 // found 92 list<DataItemId> difference(0); 93 set_difference(l.begin(), l.end(), 94 dicIter->second.begin(), dicIter->second.end(), 95 inserter(difference, difference.begin())); 96 if (!difference.empty()) { 97 difference.sort(); 98 dicIter->second.merge(difference); 99 dicIter->second.unique(); 100 } 101 } 102 else { 103 // not found 104 reqCache[client] = l; 105 } 106 } 107 108 /****************************************************************************** 109 IDataItemSubscription Overrides 110 ******************************************************************************/ 111 void SystemStatusOsObserver::subscribe( 112 const list<DataItemId>& l, IDataItemObserver* client) 113 { 114 if (nullptr == mContext.mSubscriptionObj) { 115 LOC_LOGD("%s]: Subscription object is NULL. Caching requests", __func__); 116 cacheObserverRequest(mSubscribeReqCache, l, client); 117 return; 118 } 119 120 struct HandleSubscribeReq : public LocMsg { 121 HandleSubscribeReq(SystemStatusOsObserver* parent, 122 const list<DataItemId>& l, IDataItemObserver* client) : 123 mParent(parent), mClient(client), mDataItemList(l) {} 124 virtual ~HandleSubscribeReq() {} 125 void proc() const { 126 127 if (mDataItemList.empty()) { 128 LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); 129 return; 130 } 131 132 // Handle First Response 133 list<DataItemId> pendingFirstResponseList(0); 134 mParent->mClientIndex->add(mClient, mDataItemList, pendingFirstResponseList); 135 136 // Do not send first response for only pendingFirstResponseList, 137 // instead send for all the data items (present in the cache) that 138 // have been subscribed for each time. 139 mParent->sendFirstResponse(mDataItemList, mClient); 140 141 list<DataItemId> yetToSubscribeDataItemsList(0); 142 mParent->mDataItemIndex->add(mClient, mDataItemList, yetToSubscribeDataItemsList); 143 144 // Send subscription list to framework 145 if (!yetToSubscribeDataItemsList.empty()) { 146 mParent->mContext.mSubscriptionObj->subscribe(yetToSubscribeDataItemsList, mParent); 147 LOC_LOGD("Subscribe Request sent to framework for the following"); 148 mParent->logMe(yetToSubscribeDataItemsList); 149 } 150 } 151 SystemStatusOsObserver* mParent; 152 IDataItemObserver* mClient; 153 const list<DataItemId> mDataItemList; 154 }; 155 mContext.mMsgTask->sendMsg(new (nothrow) HandleSubscribeReq(this, l, client)); 156 } 157 158 void SystemStatusOsObserver::updateSubscription( 159 const list<DataItemId>& l, IDataItemObserver* client) 160 { 161 if (nullptr == mContext.mSubscriptionObj) { 162 LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__); 163 return; 164 } 165 166 struct HandleUpdateSubscriptionReq : public LocMsg { 167 HandleUpdateSubscriptionReq(SystemStatusOsObserver* parent, 168 const list<DataItemId>& l, IDataItemObserver* client) : 169 mParent(parent), mClient(client), mDataItemList(l) {} 170 virtual ~HandleUpdateSubscriptionReq() {} 171 void proc() const { 172 if (mDataItemList.empty()) { 173 LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); 174 return; 175 } 176 177 list<DataItemId> currentlySubscribedList(0); 178 mParent->mClientIndex->getSubscribedList(mClient, currentlySubscribedList); 179 180 list<DataItemId> removeDataItemList(0); 181 set_difference(currentlySubscribedList.begin(), currentlySubscribedList.end(), 182 mDataItemList.begin(), mDataItemList.end(), 183 inserter(removeDataItemList,removeDataItemList.begin())); 184 185 // Handle First Response 186 list<DataItemId> pendingFirstResponseList(0); 187 mParent->mClientIndex->add(mClient, mDataItemList, pendingFirstResponseList); 188 189 // Send First Response 190 mParent->sendFirstResponse(pendingFirstResponseList, mClient); 191 192 list<DataItemId> yetToSubscribeDataItemsList(0); 193 mParent->mDataItemIndex->add( 194 mClient, mDataItemList, yetToSubscribeDataItemsList); 195 196 // Send subscription list to framework 197 if (!yetToSubscribeDataItemsList.empty()) { 198 mParent->mContext.mSubscriptionObj->subscribe( 199 yetToSubscribeDataItemsList, mParent); 200 LOC_LOGD("Subscribe Request sent to framework for the following"); 201 mParent->logMe(yetToSubscribeDataItemsList); 202 } 203 204 list<DataItemId> unsubscribeList(0); 205 list<DataItemId> unused(0); 206 mParent->mClientIndex->remove(mClient, removeDataItemList, unused); 207 208 if (!mParent->mClientIndex->isSubscribedClient(mClient)) { 209 mParent->mDataItemIndex->remove( 210 list<IDataItemObserver*> (1,mClient), unsubscribeList); 211 } 212 if (!unsubscribeList.empty()) { 213 // Send unsubscribe to framework 214 mParent->mContext.mSubscriptionObj->unsubscribe(unsubscribeList, mParent); 215 LOC_LOGD("Unsubscribe Request sent to framework for the following"); 216 mParent->logMe(unsubscribeList); 217 } 218 } 219 SystemStatusOsObserver* mParent; 220 IDataItemObserver* mClient; 221 const list<DataItemId> mDataItemList; 222 }; 223 mContext.mMsgTask->sendMsg(new (nothrow) HandleUpdateSubscriptionReq(this, l, client)); 224 } 225 226 void SystemStatusOsObserver::requestData( 227 const list<DataItemId>& l, IDataItemObserver* client) 228 { 229 if (nullptr == mContext.mSubscriptionObj) { 230 LOC_LOGD("%s]: Subscription object is NULL. Caching requests", __func__); 231 cacheObserverRequest(mReqDataCache, l, client); 232 return; 233 } 234 235 struct HandleRequestData : public LocMsg { 236 HandleRequestData(SystemStatusOsObserver* parent, 237 const list<DataItemId>& l, IDataItemObserver* client) : 238 mParent(parent), mClient(client), mDataItemList(l) {} 239 virtual ~HandleRequestData() {} 240 void proc() const { 241 if (mDataItemList.empty()) { 242 LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); 243 return; 244 } 245 246 list<DataItemId> yetToSubscribeDataItemsList(0); 247 mParent->mClientIndex->add( 248 mClient, mDataItemList, yetToSubscribeDataItemsList); 249 mParent->mDataItemIndex->add( 250 mClient, mDataItemList, yetToSubscribeDataItemsList); 251 252 // Send subscription list to framework 253 if (!mDataItemList.empty()) { 254 mParent->mContext.mSubscriptionObj->requestData(mDataItemList, mParent); 255 LOC_LOGD("Subscribe Request sent to framework for the following"); 256 mParent->logMe(yetToSubscribeDataItemsList); 257 } 258 } 259 SystemStatusOsObserver* mParent; 260 IDataItemObserver* mClient; 261 const list<DataItemId> mDataItemList; 262 }; 263 mContext.mMsgTask->sendMsg(new (nothrow) HandleRequestData(this, l, client)); 264 } 265 266 void SystemStatusOsObserver::unsubscribe( 267 const list<DataItemId>& l, IDataItemObserver* client) 268 { 269 if (nullptr == mContext.mSubscriptionObj) { 270 LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__); 271 return; 272 } 273 struct HandleUnsubscribeReq : public LocMsg { 274 HandleUnsubscribeReq(SystemStatusOsObserver* parent, 275 const list<DataItemId>& l, IDataItemObserver* client) : 276 mParent(parent), mClient(client), mDataItemList(l) {} 277 virtual ~HandleUnsubscribeReq() {} 278 void proc() const { 279 if (mDataItemList.empty()) { 280 LOC_LOGV("mDataItemList is empty. Nothing to do. Exiting"); 281 return; 282 } 283 284 list<DataItemId> unsubscribeList(0); 285 list<DataItemId> unused(0); 286 mParent->mClientIndex->remove(mClient, mDataItemList, unused); 287 288 for (auto each : mDataItemList) { 289 list<IDataItemObserver*> clientListSubs(0); 290 list<IDataItemObserver*> clientListOut(0); 291 mParent->mDataItemIndex->remove( 292 each, list<IDataItemObserver*> (1,mClient), clientListOut); 293 // check if there are any other subscribed client for this data item id 294 mParent->mDataItemIndex->getListOfSubscribedClients(each, clientListSubs); 295 if (clientListSubs.empty()) 296 { 297 LOC_LOGD("Client list subscribed is empty for dataitem - %d", each); 298 unsubscribeList.push_back(each); 299 } 300 } 301 302 if (!unsubscribeList.empty()) { 303 // Send unsubscribe to framework 304 mParent->mContext.mSubscriptionObj->unsubscribe(unsubscribeList, mParent); 305 LOC_LOGD("Unsubscribe Request sent to framework for the following data items"); 306 mParent->logMe(unsubscribeList); 307 } 308 } 309 SystemStatusOsObserver* mParent; 310 IDataItemObserver* mClient; 311 const list<DataItemId> mDataItemList; 312 }; 313 mContext.mMsgTask->sendMsg(new (nothrow) HandleUnsubscribeReq(this, l, client)); 314 } 315 316 void SystemStatusOsObserver::unsubscribeAll(IDataItemObserver* client) 317 { 318 if (nullptr == mContext.mSubscriptionObj) { 319 LOC_LOGE("%s:%d]: Subscription object is NULL", __func__, __LINE__); 320 return; 321 } 322 323 struct HandleUnsubscribeAllReq : public LocMsg { 324 HandleUnsubscribeAllReq(SystemStatusOsObserver* parent, 325 IDataItemObserver* client) : 326 mParent(parent), mClient(client) {} 327 virtual ~HandleUnsubscribeAllReq() {} 328 void proc() const { 329 list<IDataItemObserver*> clients(1, mClient); 330 list<DataItemId> unsubscribeList(0); 331 if(0 == mParent->mClientIndex->remove(mClient)) { 332 return; 333 } 334 mParent->mDataItemIndex->remove(clients, unsubscribeList); 335 336 if (!unsubscribeList.empty()) { 337 // Send unsubscribe to framework 338 mParent->mContext.mSubscriptionObj->unsubscribe(unsubscribeList, mParent); 339 LOC_LOGD("Unsubscribe Request sent to framework for the following data items"); 340 mParent->logMe(unsubscribeList); 341 } 342 } 343 SystemStatusOsObserver* mParent; 344 IDataItemObserver* mClient; 345 }; 346 mContext.mMsgTask->sendMsg(new (nothrow) HandleUnsubscribeAllReq(this, client)); 347 } 348 349 /****************************************************************************** 350 IDataItemObserver Overrides 351 ******************************************************************************/ 352 void SystemStatusOsObserver::notify(const list<IDataItemCore*>& dlist) 353 { 354 list<IDataItemCore*> dataItemList(0); 355 356 for (auto each : dlist) { 357 string dv; 358 each->stringify(dv); 359 LOC_LOGD("notify: DataItem In Value:%s", dv.c_str()); 360 361 IDataItemCore* di = DataItemsFactoryProxy::createNewDataItem(each->getId()); 362 if (nullptr == di) { 363 LOC_LOGE("Unable to create dataitem:%d", each->getId()); 364 return; 365 } 366 367 // Copy contents into the newly created data item 368 di->copy(each); 369 dataItemList.push_back(di); 370 // Request systemstatus to record this dataitem in its cache 371 SystemStatus* systemstatus = SystemStatus::getInstance(mContext.mMsgTask); 372 if(nullptr != systemstatus) { 373 systemstatus->eventDataItemNotify(di); 374 } 375 } 376 377 struct HandleNotify : public LocMsg { 378 HandleNotify(SystemStatusOsObserver* parent, const list<IDataItemCore*>& l) : 379 mParent(parent), mDList(l) {} 380 virtual ~HandleNotify() { 381 for (auto each : mDList) { 382 delete each; 383 } 384 } 385 void proc() const { 386 // Update Cache with received data items and prepare 387 // list of data items to be sent. 388 list<DataItemId> dataItemIdsToBeSent(0); 389 for (auto item : mDList) { 390 bool dataItemUpdated = false; 391 mParent->updateCache(item, dataItemUpdated); 392 if (dataItemUpdated) { 393 dataItemIdsToBeSent.push_back(item->getId()); 394 } 395 } 396 397 // Send data item to all subscribed clients 398 list<IDataItemObserver*> clientList(0); 399 for (auto each : dataItemIdsToBeSent) { 400 list<IDataItemObserver*> clients(0); 401 mParent->mDataItemIndex->getListOfSubscribedClients(each, clients); 402 for (auto each_cient: clients) { 403 clientList.push_back(each_cient); 404 } 405 } 406 clientList.unique(); 407 408 for (auto client : clientList) { 409 list<DataItemId> dataItemIdsSubscribedByThisClient(0); 410 list<DataItemId> dataItemIdsToBeSentForThisClient(0); 411 mParent->mClientIndex->getSubscribedList( 412 client, dataItemIdsSubscribedByThisClient); 413 dataItemIdsSubscribedByThisClient.sort(); 414 dataItemIdsToBeSent.sort(); 415 416 set_intersection(dataItemIdsToBeSent.begin(), 417 dataItemIdsToBeSent.end(), 418 dataItemIdsSubscribedByThisClient.begin(), 419 dataItemIdsSubscribedByThisClient.end(), 420 inserter(dataItemIdsToBeSentForThisClient, 421 dataItemIdsToBeSentForThisClient.begin())); 422 423 mParent->sendCachedDataItems(dataItemIdsToBeSentForThisClient, client); 424 dataItemIdsSubscribedByThisClient.clear(); 425 dataItemIdsToBeSentForThisClient.clear(); 426 } 427 } 428 SystemStatusOsObserver* mParent; 429 const list<IDataItemCore*> mDList; 430 }; 431 mContext.mMsgTask->sendMsg(new (nothrow) HandleNotify(this, dataItemList)); 432 } 433 434 /****************************************************************************** 435 IFrameworkActionReq Overrides 436 ******************************************************************************/ 437 void SystemStatusOsObserver::turnOn(DataItemId dit, int timeOut) 438 { 439 if (nullptr == mContext.mFrameworkActionReqObj) { 440 LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__); 441 return; 442 } 443 444 // Check if data item exists in mActiveRequestCount 445 map<DataItemId, int>::iterator citer = mActiveRequestCount.find(dit); 446 if (citer == mActiveRequestCount.end()) { 447 // Data item not found in map 448 // Add reference count as 1 and add dataitem to map 449 pair<DataItemId, int> cpair(dit, 1); 450 mActiveRequestCount.insert(cpair); 451 LOC_LOGD("Sending turnOn request"); 452 453 // Send action turn on to framework 454 struct HandleTurnOnMsg : public LocMsg { 455 HandleTurnOnMsg(IFrameworkActionReq* framework, 456 DataItemId dit, int timeOut) : 457 mFrameworkActionReqObj(framework), mDataItemId(dit), mTimeOut(timeOut) {} 458 virtual ~HandleTurnOnMsg() {} 459 void proc() const { 460 mFrameworkActionReqObj->turnOn(mDataItemId, mTimeOut); 461 } 462 IFrameworkActionReq* mFrameworkActionReqObj; 463 DataItemId mDataItemId; 464 int mTimeOut; 465 }; 466 mContext.mMsgTask->sendMsg(new (nothrow) HandleTurnOnMsg(this, dit, timeOut)); 467 } 468 else { 469 // Found in map, update reference count 470 citer->second++; 471 LOC_LOGD("turnOn - Data item:%d Num_refs:%d", dit, citer->second); 472 } 473 } 474 475 void SystemStatusOsObserver::turnOff(DataItemId dit) 476 { 477 if (nullptr == mContext.mFrameworkActionReqObj) { 478 LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__); 479 return; 480 } 481 482 // Check if data item exists in mActiveRequestCount 483 map<DataItemId, int>::iterator citer = mActiveRequestCount.find(dit); 484 if (citer != mActiveRequestCount.end()) { 485 // found 486 citer->second--; 487 LOC_LOGD("turnOff - Data item:%d Remaining:%d", dit, citer->second); 488 if(citer->second == 0) { 489 // if this was last reference, remove item from map and turn off module 490 mActiveRequestCount.erase(citer); 491 492 // Send action turn off to framework 493 struct HandleTurnOffMsg : public LocMsg { 494 HandleTurnOffMsg(IFrameworkActionReq* framework, DataItemId dit) : 495 mFrameworkActionReqObj(framework), mDataItemId(dit) {} 496 virtual ~HandleTurnOffMsg() {} 497 void proc() const { 498 mFrameworkActionReqObj->turnOff(mDataItemId); 499 } 500 IFrameworkActionReq* mFrameworkActionReqObj; 501 DataItemId mDataItemId; 502 }; 503 mContext.mMsgTask->sendMsg( 504 new (nothrow) HandleTurnOffMsg(mContext.mFrameworkActionReqObj, dit)); 505 } 506 } 507 } 508 509 /****************************************************************************** 510 Helpers 511 ******************************************************************************/ 512 void SystemStatusOsObserver::sendFirstResponse( 513 const list<DataItemId>& l, IDataItemObserver* to) 514 { 515 if (l.empty()) { 516 LOC_LOGV("list is empty. Nothing to do. Exiting"); 517 return; 518 } 519 520 string clientName; 521 to->getName(clientName); 522 list<IDataItemCore*> dataItems(0); 523 524 for (auto each : l) { 525 map<DataItemId, IDataItemCore*>::const_iterator citer = mDataItemCache.find(each); 526 if (citer != mDataItemCache.end()) { 527 string dv; 528 citer->second->stringify(dv); 529 LOC_LOGI("DataItem: %s >> %s", dv.c_str(), clientName.c_str()); 530 dataItems.push_back(citer->second); 531 } 532 } 533 if (dataItems.empty()) { 534 LOC_LOGV("No items to notify. Nothing to do. Exiting"); 535 return; 536 } 537 to->notify(dataItems); 538 } 539 540 void SystemStatusOsObserver::sendCachedDataItems( 541 const list<DataItemId>& l, IDataItemObserver* to) 542 { 543 string clientName; 544 to->getName(clientName); 545 list<IDataItemCore*> dataItems(0); 546 547 for (auto each : l) { 548 string dv; 549 IDataItemCore* di = mDataItemCache[each]; 550 di->stringify(dv); 551 LOC_LOGI("DataItem: %s >> %s", dv.c_str(), clientName.c_str()); 552 dataItems.push_back(di); 553 } 554 to->notify(dataItems); 555 } 556 557 void SystemStatusOsObserver::updateCache(IDataItemCore* d, bool& dataItemUpdated) 558 { 559 if (nullptr == d) { 560 return; 561 } 562 563 // Check if data item exists in cache 564 map<DataItemId, IDataItemCore*>::iterator citer = 565 mDataItemCache.find(d->getId()); 566 if (citer == mDataItemCache.end()) { 567 // New data item; not found in cache 568 IDataItemCore* dataitem = DataItemsFactoryProxy::createNewDataItem(d->getId()); 569 if (nullptr == dataitem) { 570 return; 571 } 572 573 // Copy the contents of the data item 574 dataitem->copy(d); 575 pair<DataItemId, IDataItemCore*> cpair(d->getId(), dataitem); 576 // Insert in mDataItemCache 577 mDataItemCache.insert(cpair); 578 dataItemUpdated = true; 579 } 580 else { 581 // Found in cache; Update cache if necessary 582 if(0 == citer->second->copy(d, &dataItemUpdated)) { 583 return; 584 } 585 } 586 587 if (dataItemUpdated) { 588 LOC_LOGV("DataItem:%d updated:%d", d->getId(), dataItemUpdated); 589 } 590 } 591 592 } // namespace loc_core 593 594