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