1 /* Copyright (c) 2015-2020, 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 <DataItemsFactoryProxy.h> 36 37 namespace loc_core 38 { 39 template <typename CINT, typename COUT> 40 COUT SystemStatusOsObserver::containerTransfer(CINT& inContainer) { 41 COUT outContainer(0); 42 for (auto item : inContainer) { 43 outContainer.insert(outContainer.begin(), item); 44 } 45 return outContainer; 46 } 47 48 SystemStatusOsObserver::~SystemStatusOsObserver() { 49 // Close data-item library handle 50 DataItemsFactoryProxy::closeDataItemLibraryHandle(); 51 52 // Destroy cache 53 for (auto each : mDataItemCache) { 54 if (nullptr != each.second) { 55 delete each.second; 56 } 57 } 58 59 mDataItemCache.clear(); 60 } 61 62 void SystemStatusOsObserver::setSubscriptionObj(IDataItemSubscription* subscriptionObj) 63 { 64 struct SetSubsObj : public LocMsg { 65 ObserverContext& mContext; 66 IDataItemSubscription* mSubsObj; 67 inline SetSubsObj(ObserverContext& context, IDataItemSubscription* subscriptionObj) : 68 mContext(context), mSubsObj(subscriptionObj) {} 69 void proc() const { 70 mContext.mSubscriptionObj = mSubsObj; 71 72 if (!mContext.mSSObserver->mDataItemToClients.empty()) { 73 list<DataItemId> dis( 74 containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( 75 mContext.mSSObserver->mDataItemToClients.getKeys())); 76 mContext.mSubscriptionObj->subscribe(dis, mContext.mSSObserver); 77 mContext.mSubscriptionObj->requestData(dis, mContext.mSSObserver); 78 } 79 } 80 }; 81 82 if (nullptr == subscriptionObj) { 83 LOC_LOGw("subscriptionObj is NULL"); 84 } else { 85 mContext.mMsgTask->sendMsg(new SetSubsObj(mContext, subscriptionObj)); 86 } 87 } 88 89 /****************************************************************************** 90 IDataItemSubscription Overrides 91 ******************************************************************************/ 92 void SystemStatusOsObserver::subscribe(const list<DataItemId>& l, IDataItemObserver* client, 93 bool toRequestData) 94 { 95 struct HandleSubscribeReq : public LocMsg { 96 inline HandleSubscribeReq(SystemStatusOsObserver* parent, 97 list<DataItemId>& l, IDataItemObserver* client, bool requestData) : 98 mParent(parent), mClient(client), 99 mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)), 100 diItemlist(l), 101 mToRequestData(requestData) {} 102 103 void proc() const { 104 unordered_set<DataItemId> dataItemsToSubscribe(0); 105 mParent->mDataItemToClients.add(mDataItemSet, {mClient}, &dataItemsToSubscribe); 106 mParent->mClientToDataItems.add(mClient, mDataItemSet); 107 108 mParent->sendCachedDataItems(mDataItemSet, mClient); 109 110 // Send subscription set to framework 111 if (nullptr != mParent->mContext.mSubscriptionObj) { 112 if (mToRequestData) { 113 LOC_LOGD("Request Data sent to framework for the following"); 114 mParent->mContext.mSubscriptionObj->requestData(diItemlist, mParent); 115 } else if (!dataItemsToSubscribe.empty()) { 116 LOC_LOGD("Subscribe Request sent to framework for the following"); 117 mParent->logMe(dataItemsToSubscribe); 118 mParent->mContext.mSubscriptionObj->subscribe( 119 containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( 120 std::move(dataItemsToSubscribe)), 121 mParent); 122 } 123 } 124 } 125 mutable SystemStatusOsObserver* mParent; 126 IDataItemObserver* mClient; 127 const unordered_set<DataItemId> mDataItemSet; 128 const list<DataItemId> diItemlist; 129 bool mToRequestData; 130 }; 131 132 if (l.empty() || nullptr == client) { 133 LOC_LOGw("Data item set is empty or client is nullptr"); 134 } else { 135 mContext.mMsgTask->sendMsg( 136 new HandleSubscribeReq(this, (list<DataItemId>&)l, client, toRequestData)); 137 } 138 } 139 140 void SystemStatusOsObserver::updateSubscription( 141 const list<DataItemId>& l, IDataItemObserver* client) 142 { 143 struct HandleUpdateSubscriptionReq : public LocMsg { 144 HandleUpdateSubscriptionReq(SystemStatusOsObserver* parent, 145 list<DataItemId>& l, IDataItemObserver* client) : 146 mParent(parent), mClient(client), 147 mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {} 148 149 void proc() const { 150 unordered_set<DataItemId> dataItemsToSubscribe(0); 151 unordered_set<DataItemId> dataItemsToUnsubscribe(0); 152 unordered_set<IDataItemObserver*> clients({mClient}); 153 // below removes clients from all entries keyed with the return of the 154 // mClientToDataItems.update() call. If leaving an empty set of clients as the 155 // result, the entire entry will be removed. dataItemsToUnsubscribe will be 156 // populated to keep the keys of the removed entries. 157 mParent->mDataItemToClients.trimOrRemove( 158 // this call updates <IDataItemObserver*, DataItemId> map; removes 159 // the DataItemId's that are not new to the clietn from mDataItemSet; 160 // and returns a set of mDataItemSet's that are no longer used by client. 161 // This unused set of mDataItemSet's is passed to trimOrRemove method of 162 // <DataItemId, IDataItemObserver*> map to remove the client from the 163 // corresponding entries, and gets a set of the entries that are 164 // removed from the <DataItemId, IDataItemObserver*> map as a result. 165 mParent->mClientToDataItems.update(mClient, 166 (unordered_set<DataItemId>&)mDataItemSet), 167 clients, &dataItemsToUnsubscribe, nullptr); 168 // below adds mClient to <DataItemId, IDataItemObserver*> map, and populates 169 // new keys added to that map, which are DataItemIds to be subscribed. 170 mParent->mDataItemToClients.add(mDataItemSet, clients, &dataItemsToSubscribe); 171 172 // Send First Response 173 mParent->sendCachedDataItems(mDataItemSet, mClient); 174 175 if (nullptr != mParent->mContext.mSubscriptionObj) { 176 // Send subscription set to framework 177 if (!dataItemsToSubscribe.empty()) { 178 LOC_LOGD("Subscribe Request sent to framework for the following"); 179 mParent->logMe(dataItemsToSubscribe); 180 181 mParent->mContext.mSubscriptionObj->subscribe( 182 containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( 183 std::move(dataItemsToSubscribe)), 184 mParent); 185 } 186 187 // Send unsubscribe to framework 188 if (!dataItemsToUnsubscribe.empty()) { 189 LOC_LOGD("Unsubscribe Request sent to framework for the following"); 190 mParent->logMe(dataItemsToUnsubscribe); 191 192 mParent->mContext.mSubscriptionObj->unsubscribe( 193 containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( 194 std::move(dataItemsToUnsubscribe)), 195 mParent); 196 } 197 } 198 } 199 SystemStatusOsObserver* mParent; 200 IDataItemObserver* mClient; 201 unordered_set<DataItemId> mDataItemSet; 202 }; 203 204 if (l.empty() || nullptr == client) { 205 LOC_LOGw("Data item set is empty or client is nullptr"); 206 } else { 207 mContext.mMsgTask->sendMsg( 208 new HandleUpdateSubscriptionReq(this, (list<DataItemId>&)l, client)); 209 } 210 } 211 212 void SystemStatusOsObserver::unsubscribe( 213 const list<DataItemId>& l, IDataItemObserver* client) 214 { 215 struct HandleUnsubscribeReq : public LocMsg { 216 HandleUnsubscribeReq(SystemStatusOsObserver* parent, 217 list<DataItemId>& l, IDataItemObserver* client) : 218 mParent(parent), mClient(client), 219 mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {} 220 221 void proc() const { 222 unordered_set<DataItemId> dataItemsUnusedByClient(0); 223 unordered_set<IDataItemObserver*> clientToRemove(0); 224 mParent->mClientToDataItems.trimOrRemove({mClient}, mDataItemSet, &clientToRemove, 225 &dataItemsUnusedByClient); 226 unordered_set<DataItemId> dataItemsToUnsubscribe(0); 227 mParent->mDataItemToClients.trimOrRemove(dataItemsUnusedByClient, {mClient}, 228 &dataItemsToUnsubscribe, nullptr); 229 230 if (nullptr != mParent->mContext.mSubscriptionObj && !dataItemsToUnsubscribe.empty()) { 231 LOC_LOGD("Unsubscribe Request sent to framework for the following data items"); 232 mParent->logMe(dataItemsToUnsubscribe); 233 234 // Send unsubscribe to framework 235 mParent->mContext.mSubscriptionObj->unsubscribe( 236 containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( 237 std::move(dataItemsToUnsubscribe)), 238 mParent); 239 } 240 } 241 SystemStatusOsObserver* mParent; 242 IDataItemObserver* mClient; 243 unordered_set<DataItemId> mDataItemSet; 244 }; 245 246 if (l.empty() || nullptr == client) { 247 LOC_LOGw("Data item set is empty or client is nullptr"); 248 } else { 249 mContext.mMsgTask->sendMsg(new HandleUnsubscribeReq(this, (list<DataItemId>&)l, client)); 250 } 251 } 252 253 void SystemStatusOsObserver::unsubscribeAll(IDataItemObserver* client) 254 { 255 struct HandleUnsubscribeAllReq : public LocMsg { 256 HandleUnsubscribeAllReq(SystemStatusOsObserver* parent, 257 IDataItemObserver* client) : 258 mParent(parent), mClient(client) {} 259 260 void proc() const { 261 unordered_set<DataItemId> diByClient = mParent->mClientToDataItems.getValSet(mClient); 262 if (!diByClient.empty()) { 263 unordered_set<DataItemId> dataItemsToUnsubscribe; 264 mParent->mClientToDataItems.remove(mClient); 265 mParent->mDataItemToClients.trimOrRemove(diByClient, {mClient}, 266 &dataItemsToUnsubscribe, nullptr); 267 268 if (!dataItemsToUnsubscribe.empty() && 269 nullptr != mParent->mContext.mSubscriptionObj) { 270 271 LOC_LOGD("Unsubscribe Request sent to framework for the following data items"); 272 mParent->logMe(dataItemsToUnsubscribe); 273 274 // Send unsubscribe to framework 275 mParent->mContext.mSubscriptionObj->unsubscribe( 276 containerTransfer<unordered_set<DataItemId>, list<DataItemId>>( 277 std::move(dataItemsToUnsubscribe)), 278 mParent); 279 } 280 } 281 } 282 SystemStatusOsObserver* mParent; 283 IDataItemObserver* mClient; 284 }; 285 286 if (nullptr == client) { 287 LOC_LOGw("Data item set is empty or client is nullptr"); 288 } else { 289 mContext.mMsgTask->sendMsg(new HandleUnsubscribeAllReq(this, client)); 290 } 291 } 292 293 /****************************************************************************** 294 IDataItemObserver Overrides 295 ******************************************************************************/ 296 void SystemStatusOsObserver::notify(const list<IDataItemCore*>& dlist) 297 { 298 struct HandleNotify : public LocMsg { 299 HandleNotify(SystemStatusOsObserver* parent, vector<IDataItemCore*>& v) : 300 mParent(parent), mDiVec(std::move(v)) {} 301 302 inline virtual ~HandleNotify() { 303 for (auto item : mDiVec) { 304 delete item; 305 } 306 } 307 308 void proc() const { 309 // Update Cache with received data items and prepare 310 // list of data items to be sent. 311 unordered_set<DataItemId> dataItemIdsToBeSent(0); 312 for (auto item : mDiVec) { 313 if (mParent->updateCache(item)) { 314 dataItemIdsToBeSent.insert(item->getId()); 315 } 316 } 317 318 // Send data item to all subscribed clients 319 unordered_set<IDataItemObserver*> clientSet(0); 320 for (auto each : dataItemIdsToBeSent) { 321 auto clients = mParent->mDataItemToClients.getValSetPtr(each); 322 if (nullptr != clients) { 323 clientSet.insert(clients->begin(), clients->end()); 324 } 325 } 326 327 for (auto client : clientSet) { 328 unordered_set<DataItemId> dataItemIdsForThisClient( 329 mParent->mClientToDataItems.getValSet(client)); 330 for (auto itr = dataItemIdsForThisClient.begin(); 331 itr != dataItemIdsForThisClient.end(); ) { 332 if (dataItemIdsToBeSent.find(*itr) == dataItemIdsToBeSent.end()) { 333 itr = dataItemIdsForThisClient.erase(itr); 334 } else { 335 itr++; 336 } 337 } 338 339 mParent->sendCachedDataItems(dataItemIdsForThisClient, client); 340 } 341 } 342 SystemStatusOsObserver* mParent; 343 const vector<IDataItemCore*> mDiVec; 344 }; 345 346 if (!dlist.empty()) { 347 vector<IDataItemCore*> dataItemVec(dlist.size()); 348 349 for (auto each : dlist) { 350 351 IDataItemCore* di = DataItemsFactoryProxy::createNewDataItem(each->getId()); 352 if (nullptr == di) { 353 LOC_LOGw("Unable to create dataitem:%d", each->getId()); 354 continue; 355 } 356 357 // Copy contents into the newly created data item 358 di->copy(each); 359 360 // add this dataitem if updated from last one 361 dataItemVec.push_back(di); 362 IF_LOC_LOGD { 363 string dv; 364 di->stringify(dv); 365 LOC_LOGd("notify: DataItem In Value:%s", dv.c_str()); 366 } 367 } 368 369 if (!dataItemVec.empty()) { 370 mContext.mMsgTask->sendMsg(new HandleNotify(this, dataItemVec)); 371 } 372 } 373 } 374 375 /****************************************************************************** 376 IFrameworkActionReq Overrides 377 ******************************************************************************/ 378 void SystemStatusOsObserver::turnOn(DataItemId dit, int timeOut) 379 { 380 if (nullptr == mContext.mFrameworkActionReqObj) { 381 LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__); 382 return; 383 } 384 385 // Check if data item exists in mActiveRequestCount 386 DataItemIdToInt::iterator citer = mActiveRequestCount.find(dit); 387 if (citer == mActiveRequestCount.end()) { 388 // Data item not found in map 389 // Add reference count as 1 and add dataitem to map 390 pair<DataItemId, int> cpair(dit, 1); 391 mActiveRequestCount.insert(cpair); 392 LOC_LOGD("Sending turnOn request"); 393 394 // Send action turn on to framework 395 struct HandleTurnOnMsg : public LocMsg { 396 HandleTurnOnMsg(IFrameworkActionReq* framework, 397 DataItemId dit, int timeOut) : 398 mFrameworkActionReqObj(framework), mDataItemId(dit), mTimeOut(timeOut) {} 399 virtual ~HandleTurnOnMsg() {} 400 void proc() const { 401 mFrameworkActionReqObj->turnOn(mDataItemId, mTimeOut); 402 } 403 IFrameworkActionReq* mFrameworkActionReqObj; 404 DataItemId mDataItemId; 405 int mTimeOut; 406 }; 407 mContext.mMsgTask->sendMsg( 408 new (nothrow) HandleTurnOnMsg(mContext.mFrameworkActionReqObj, dit, timeOut)); 409 } 410 else { 411 // Found in map, update reference count 412 citer->second++; 413 LOC_LOGD("turnOn - Data item:%d Num_refs:%d", dit, citer->second); 414 } 415 } 416 417 void SystemStatusOsObserver::turnOff(DataItemId dit) 418 { 419 if (nullptr == mContext.mFrameworkActionReqObj) { 420 LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__); 421 return; 422 } 423 424 // Check if data item exists in mActiveRequestCount 425 DataItemIdToInt::iterator citer = mActiveRequestCount.find(dit); 426 if (citer != mActiveRequestCount.end()) { 427 // found 428 citer->second--; 429 LOC_LOGD("turnOff - Data item:%d Remaining:%d", dit, citer->second); 430 if(citer->second == 0) { 431 // if this was last reference, remove item from map and turn off module 432 mActiveRequestCount.erase(citer); 433 434 // Send action turn off to framework 435 struct HandleTurnOffMsg : public LocMsg { 436 HandleTurnOffMsg(IFrameworkActionReq* framework, DataItemId dit) : 437 mFrameworkActionReqObj(framework), mDataItemId(dit) {} 438 virtual ~HandleTurnOffMsg() {} 439 void proc() const { 440 mFrameworkActionReqObj->turnOff(mDataItemId); 441 } 442 IFrameworkActionReq* mFrameworkActionReqObj; 443 DataItemId mDataItemId; 444 }; 445 mContext.mMsgTask->sendMsg( 446 new (nothrow) HandleTurnOffMsg(mContext.mFrameworkActionReqObj, dit)); 447 } 448 } 449 } 450 451 #ifdef USE_GLIB 452 bool SystemStatusOsObserver::connectBackhaul() 453 { 454 bool result = false; 455 456 if (mContext.mFrameworkActionReqObj != NULL) { 457 struct HandleConnectBackhaul : public LocMsg { 458 HandleConnectBackhaul(IFrameworkActionReq* fwkActReq) : 459 mFwkActionReqObj(fwkActReq) {} 460 virtual ~HandleConnectBackhaul() {} 461 void proc() const { 462 LOC_LOGD("HandleConnectBackhaul"); 463 mFwkActionReqObj->connectBackhaul(); 464 } 465 IFrameworkActionReq* mFwkActionReqObj; 466 }; 467 mContext.mMsgTask->sendMsg( 468 new (nothrow) HandleConnectBackhaul(mContext.mFrameworkActionReqObj)); 469 result = true; 470 } 471 else { 472 ++mBackHaulConnectReqCount; 473 LOC_LOGE("Framework action request object is NULL.Caching connect request: %d", 474 mBackHaulConnectReqCount); 475 result = false; 476 } 477 return result; 478 479 } 480 481 bool SystemStatusOsObserver::disconnectBackhaul() 482 { 483 bool result = false; 484 485 if (mContext.mFrameworkActionReqObj != NULL) { 486 struct HandleDisconnectBackhaul : public LocMsg { 487 HandleDisconnectBackhaul(IFrameworkActionReq* fwkActReq) : 488 mFwkActionReqObj(fwkActReq) {} 489 virtual ~HandleDisconnectBackhaul() {} 490 void proc() const { 491 LOC_LOGD("HandleDisconnectBackhaul"); 492 mFwkActionReqObj->disconnectBackhaul(); 493 } 494 IFrameworkActionReq* mFwkActionReqObj; 495 }; 496 mContext.mMsgTask->sendMsg( 497 new (nothrow) HandleDisconnectBackhaul(mContext.mFrameworkActionReqObj)); 498 } 499 else { 500 if (mBackHaulConnectReqCount > 0) { 501 --mBackHaulConnectReqCount; 502 } 503 LOC_LOGE("Framework action request object is NULL.Caching disconnect request: %d", 504 mBackHaulConnectReqCount); 505 result = false; 506 } 507 return result; 508 } 509 #endif 510 /****************************************************************************** 511 Helpers 512 ******************************************************************************/ 513 void SystemStatusOsObserver::sendCachedDataItems( 514 const unordered_set<DataItemId>& s, IDataItemObserver* to) 515 { 516 if (nullptr == to) { 517 LOC_LOGv("client pointer is NULL."); 518 } else { 519 string clientName; 520 to->getName(clientName); 521 list<IDataItemCore*> dataItems(0); 522 523 for (auto each : s) { 524 auto citer = mDataItemCache.find(each); 525 if (citer != mDataItemCache.end()) { 526 string dv; 527 citer->second->stringify(dv); 528 LOC_LOGI("DataItem: %s >> %s", dv.c_str(), clientName.c_str()); 529 dataItems.push_front(citer->second); 530 } 531 } 532 533 if (dataItems.empty()) { 534 LOC_LOGv("No items to notify."); 535 } else { 536 to->notify(dataItems); 537 } 538 } 539 } 540 541 bool SystemStatusOsObserver::updateCache(IDataItemCore* d) 542 { 543 bool dataItemUpdated = false; 544 545 // Request systemstatus to record this dataitem in its cache 546 // if the return is false, it means that SystemStatus is not 547 // handling it, so SystemStatusOsObserver also doesn't. 548 // So it has to be true to proceed. 549 if (nullptr != d && mSystemStatus->eventDataItemNotify(d)) { 550 auto citer = mDataItemCache.find(d->getId()); 551 if (citer == mDataItemCache.end()) { 552 // New data item; not found in cache 553 IDataItemCore* dataitem = DataItemsFactoryProxy::createNewDataItem(d->getId()); 554 if (nullptr != dataitem) { 555 // Copy the contents of the data item 556 dataitem->copy(d); 557 // Insert in mDataItemCache 558 mDataItemCache.insert(std::make_pair(d->getId(), dataitem)); 559 dataItemUpdated = true; 560 } 561 } else { 562 // Found in cache; Update cache if necessary 563 citer->second->copy(d, &dataItemUpdated); 564 } 565 566 if (dataItemUpdated) { 567 LOC_LOGV("DataItem:%d updated:%d", d->getId(), dataItemUpdated); 568 } 569 } 570 571 return dataItemUpdated; 572 } 573 574 } // namespace loc_core 575 576