diff -r 5cc91383ab1e -r 7333d7932ef7 installationservices/swinstallationfw/source/sifnotification.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/installationservices/swinstallationfw/source/sifnotification.cpp Tue Aug 31 15:21:33 2010 +0300 @@ -0,0 +1,826 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* This file implements the SifNotifier library +* +*/ + +#include +#include +#include +#include +#include "sifnotification_internal.h" +#include +#include "e32property.h" +#include "scrclient.inl" +#include "usiflog.h" + + +using namespace Usif; + +/** + * A global method which is used by both the publisher and subscriber code to retrieve data. + * + */ +void GetDataL(TUint aKey, TInt& aBufferSize, RBuf8& aData) + { + aData.CreateL(aBufferSize); + aData.CleanupClosePushL(); + TInt err = RProperty::Get(KUidSystemCategory, aKey, aData); + + // If the buffer size is too small. + while (err == KErrOverflow) + { + aBufferSize*=2; + aData.ReAllocL(aBufferSize); + err = RProperty::Get(KUidSystemCategory, aKey, aData); + } + + User::LeaveIfError(err); + CleanupStack::Pop(); + } + +//////////////////////////// +// CPublishSifOperationInfo +//////////////////////////// + +CPublishSifOperationInfo::CPublishSifOperationInfo(): + iBufferSize(KBufferSize) + { + // empty + } + +CPublishSifOperationInfo::~CPublishSifOperationInfo() + { + delete iDeleteTimer; + if (iStartEndKey != 0) + { + RProperty::Delete(KUidSystemCategory, iStartEndKey); + RProperty::Delete(KUidSystemCategory, (iStartEndKey+1)); + } + } + +EXPORT_C CPublishSifOperationInfo* CPublishSifOperationInfo::NewL() + { + CPublishSifOperationInfo *self = CPublishSifOperationInfo::NewLC(); + CleanupStack::Pop(self); + return self; + } + +EXPORT_C CPublishSifOperationInfo* CPublishSifOperationInfo::NewLC() + { + CPublishSifOperationInfo *self = new(ELeave) CPublishSifOperationInfo(); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +void CPublishSifOperationInfo::ConstructL() + { + + } + +TUint CPublishSifOperationInfo::AvailableKeyL() + { + TBuf8 buf; + for(TInt i=0; i< KMaxNumberOfOperations-1; ++i) + { + if(KErrNotFound == RProperty::Get(KUidSystemCategory, KSifPropertyTable[i], buf)) + { + return KSifPropertyTable[i]; + } + } + + User::Leave(KErrInUse); + return KErrNone; // Keep compiler happy. + } + +TUint CPublishSifOperationInfo::KeyForGlobalComponentIdL(const TDesC& aGlobalComponentId) + { + TBuf8 buf; + //Get all ongoing operations + User::LeaveIfError(RProperty::Get(KUidSystemCategory, KSifOperationKey, buf)); + + RDesReadStream readStream(buf); + CleanupClosePushL(readStream); + CSifOperationKey* opKey = CSifOperationKey::NewL(readStream); + CleanupStack::PopAndDestroy(&readStream); + CleanupStack::PushL(opKey); + + RArray startEndKeyArr = opKey->StartEndKeys(); + // Get the data for all the ongoing operations and check for global component id + for (TInt i=0; i(readStream.ReadInt32L()); + if(opType != ESifOperationStart) + { + CleanupStack::PopAndDestroy(2, &startDatabuf); + continue; + } + + // Release the stream and reopen it. + readStream.Release(); + readStream.Open(startDatabuf); + + CSifOperationStartData* startObj = CSifOperationStartData::NewL(readStream); + CleanupStack::PushL(startObj); + // Check if the global component id is the same as what we are looking for + if( KErrNone == aGlobalComponentId.Compare(startObj->GlobalComponentId())) + { + TInt key = startEndKeyArr[i]; + CleanupStack::PopAndDestroy(4, opKey); + return key; + } + CleanupStack::PopAndDestroy(3, &startDatabuf); + } + CleanupStack::PopAndDestroy(opKey); + + // Could not find corresponding key + User::Leave(KErrNotFound); + return KErrNone; // Keep compiler happy. + } + +void CPublishSifOperationInfo::SetKeyToDelete(TUint aStartEndKey) + { + iStartEndKey = aStartEndKey; + } + +EXPORT_C void CPublishSifOperationInfo::PublishStartL(CSifOperationStartData& aSifOperationStartData) + { + // Get Property key from free pool which could be used for this operation. + TUint key = AvailableKeyL(); + + // Define key from free pool. Start data could be bigger than 512 bytes, hence using ELargeByteArray. + User::LeaveIfError(RProperty::Define(KUidSystemCategory, key, RProperty::ELargeByteArray,KSecurityPolicyWDD,KSecurityPolicyNone,KStartBufLength)); + + // Store this key and delete it in case of any leaves + SetKeyToDelete(key); + + // Publish start info of operation in defined key. + RBuf8 bufStartData; + bufStartData.CleanupClosePushL(); + ExternalizeRefObjectL(aSifOperationStartData, bufStartData); + + User::LeaveIfError(RProperty::Set(KUidSystemCategory, key, bufStartData)); + + CleanupStack::PopAndDestroy(&bufStartData); + + // Define key for progress data for this operation. + User::LeaveIfError(RProperty::Define(KUidSystemCategory, (key+1), RProperty::EByteArray,KSecurityPolicyWDD,KSecurityPolicyNone, KProgressBufLength)); + + // Publish(append this key to existing info) the newly defined key in the global SIF key. + TBuf8 buf; + + User::LeaveIfError(RProperty::Get(KUidSystemCategory, KSifOperationKey, buf)); + + RDesReadStream stream(buf); + CleanupClosePushL(stream); + + // Retrieve current keys. + CSifOperationKey* currentKeys = CSifOperationKey::NewL(stream); + CleanupStack::PopAndDestroy(&stream); + + CleanupStack::PushL(currentKeys); + + // Append the new key. + currentKeys->AddKeyL(key); + + RBuf8 bufOperationKeys; + bufOperationKeys.CleanupClosePushL(); + ExternalizeRefObjectL(*currentKeys, bufOperationKeys); + + // Publish the new set of keys. + User::LeaveIfError(RProperty::Set(KUidSystemCategory, KSifOperationKey, bufOperationKeys)); + + // Everything finished fine, we need not delete the keys defined above. + SetKeyToDelete(0); + + CleanupStack::PopAndDestroy(2, currentKeys); + } + +EXPORT_C void CPublishSifOperationInfo::PublishProgressL(CSifOperationProgressData& aSifOperationProgressData) + { + TUint startEndKey = 0; + + HBufC16 *compGlobalId = aSifOperationProgressData.GlobalComponentId().AllocLC(); + //Get the key defined for this operation + startEndKey = KeyForGlobalComponentIdL(compGlobalId->Des()); + CleanupStack::PopAndDestroy(compGlobalId); + + //Publish progress info of operation in defined key + RBuf8 bufProgressData; + bufProgressData.CleanupClosePushL(); + ExternalizeRefObjectL(aSifOperationProgressData, bufProgressData); + User::LeaveIfError(RProperty::Set(KUidSystemCategory, (startEndKey+1), bufProgressData)); + CleanupStack::PopAndDestroy(&bufProgressData); + } + +EXPORT_C void CPublishSifOperationInfo::PublishCompletionL(CSifOperationEndData& aSifOperationEndData) + { + TUint endKey = 0; + HBufC *compGlobalId = aSifOperationEndData.GlobalComponentId().AllocLC(); + //Get the key defined for this operation + endKey = KeyForGlobalComponentIdL(compGlobalId->Des()); + CleanupStack::PopAndDestroy(compGlobalId); + + // Store this key and delete it in case of any leaves + SetKeyToDelete(endKey); + + //Publish end info of operation in defined key + RBuf8 bufEndData; + bufEndData.CleanupClosePushL(); + ExternalizeRefObjectL(aSifOperationEndData, bufEndData); + + User::LeaveIfError(RProperty::Set(KUidSystemCategory, endKey, bufEndData)); + CleanupStack::PopAndDestroy(&bufEndData); + + // Wait for KDeleteKeyDelay seconds before deleting this key. + if(iDeleteTimer) + iDeleteTimer->Cancel(); + delete iDeleteTimer; + iDeleteTimer = CDeleteKeyTimer::NewL(endKey); + + // Everything finished fine, we need not delete the keys defined for this operation + SetKeyToDelete(0); + + iDeleteTimer->Start(); + + } + + + +////////////////////////// +// CSifOperationsNotifier +////////////////////////// + + +EXPORT_C CSifOperationsNotifier* CSifOperationsNotifier::NewL(MSifOperationsHandler& aHandler) + { + CSifOperationsNotifier* self = CSifOperationsNotifier::NewLC(aHandler); + CleanupStack::Pop(self); + return self; + } + + +EXPORT_C CSifOperationsNotifier* CSifOperationsNotifier::NewLC(MSifOperationsHandler& aHandler) + { + CSifOperationsNotifier* self = new (ELeave) CSifOperationsNotifier(aHandler); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +CSifOperationsNotifier::CSifOperationsNotifier(MSifOperationsHandler& aHandler): + CActive(EPriorityNormal), + iHandler(aHandler), + iBufferSize(KBufferSize) + { + //Empty + } + + +void CSifOperationsNotifier::ConstructL() + { + CActiveScheduler::Add(this); + iProperty.Attach(KUidSystemCategory,KSifOperationKey,EOwnerThread); + + // On first start, the notifier looks for any active operations and + // notifies the client. + iNotifierState = EFirstStart; + + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + SetActive(); + } + + +void CSifOperationsNotifier::RunL() + { + User::LeaveIfError(iStatus.Int()); + + // Resubscribe for any changes to the global key. + WaitForChangeL(); + + if( iNotifierState == EFirstStart) + { + // Notify the client of any active operation. + ActiveOperationsNotificationL(); + iNotifierState = EWaitForChange; + return; + } + + // Global key change notification received. + RArray newKeyArray; + GetKeysL(newKeyArray); + CleanupClosePushL(newKeyArray); + + if(iKeyArray.Count() < newKeyArray.Count()) + { + // New Keys added. + RBuf8 externalizedBuffer; + externalizedBuffer.CleanupClosePushL(); + + // Retrieve the new keys and send the start operation notification to each. + for(TInt i = iKeyArray.Count(); i< newKeyArray.Count(); ++i) + { + externalizedBuffer.Close(); + GetDataL(newKeyArray[i], iBufferSize, externalizedBuffer); + + RDesReadStream stream(externalizedBuffer); + CleanupClosePushL(stream); + // Read the first 4 bytes + TSifOperation opType = static_cast(stream.ReadInt32L()); + if(opType != ESifOperationStart) + { + CleanupStack::PopAndDestroy(&stream); + continue; + } + + // Release the stream and reopen it. + stream.Release(); + stream.Open(externalizedBuffer); + + CSifOperationStartData* startData = CSifOperationStartData::NewL(stream); + CleanupStack::PushL(startData); + + //Update iKeyArray with the new key. + iKeyArray.AppendL(newKeyArray[i]); + + iHandler.StartOperationHandler(newKeyArray[i], *startData); + CleanupStack::PopAndDestroy(2, &stream); + + } + CleanupStack::PopAndDestroy(&externalizedBuffer); + } + else if (iKeyArray.Count() > newKeyArray.Count()) + { + // Keys removed. + for(TInt i = 0; i(stream.ReadUint32L()); + if(opType != ESifOperationStart) + { + // Ignore this key and continue. + CleanupStack::PopAndDestroy(2, &externalizedBuffer); + continue; + } + // Release the stream and reopen it. + stream.Release(); + stream.Open(externalizedBuffer); + + CSifOperationStartData* startData = CSifOperationStartData::NewL(stream); + CleanupStack::PushL(startData); + iHandler.StartOperationHandler(iKeyArray[i], *startData); + CleanupStack::PopAndDestroy(startData); + + CleanupStack::PopAndDestroy(2, &externalizedBuffer); + } + + } +void CSifOperationsNotifier::WaitForChangeL() + { + iProperty.Subscribe(iStatus); + SetActive(); + } + + +void CSifOperationsNotifier::GetKeysL(RArray& aKeys) + { + TBuf8 keysBuffer; + User::LeaveIfError(iProperty.Get(keysBuffer)); + + RDesReadStream stream(keysBuffer); + CleanupClosePushL(stream); + + // Construct the CSifOperationKey object from the buffer. + CSifOperationKey* opKey = CSifOperationKey::NewL(stream); + CleanupStack::PushL(opKey); + + for(TInt i=0; iStartEndKeys().Count(); ++i) + { + aKeys.AppendL(opKey->StartEndKeys()[i]); + } + + CleanupStack::PopAndDestroy(2, &stream); + } + + +EXPORT_C void CSifOperationsNotifier::SubscribeL(TUint aKey, TBool aSubscribeForProgressNotifications) + { + User::LeaveIfError(iKeyArray.Find(aKey)); + + // Start End notifier. + CSifNotifierBase* startEndNotifier = CSifNotifierBase::NewLC(iHandler, aKey, CSifNotifierBase::EStartEndNotifier); + iNotifierArray.AppendL(startEndNotifier); + CleanupStack::Pop(startEndNotifier); + + if(aSubscribeForProgressNotifications) + { + // Progress Notifier. + CSifNotifierBase* progressNotifier = CSifNotifierBase::NewLC(iHandler, aKey+1, CSifNotifierBase::EProgressNotifier); + iNotifierArray.AppendL(progressNotifier); + CleanupStack::Pop(progressNotifier); + } + } + + +EXPORT_C void CSifOperationsNotifier::CancelSubscribeL(TUint aKey) + { + TInt index = iKeyArray.Find(aKey); + + if(index == KErrNotFound) + { + // No need to leave. + return; + } + + for(TInt i=0; i< iNotifierArray.Count(); ++i) + { + + if(iNotifierArray[i]->Key() == aKey) + { + delete iNotifierArray[i]; + iNotifierArray.Remove(i); + + // Delete progress notification object also, if present. + // i now points to the next element + if( i <= iNotifierArray.Count()-1 && iNotifierArray[i]->Key() == aKey+1) + { + delete iNotifierArray[i]; + iNotifierArray.Remove(i); + } + } + + } + + } + + +EXPORT_C void CSifOperationsNotifier::CancelSubscribeL() + { + //Destroy all the notifiers. + Cancel(); + } + + +void CSifOperationsNotifier::DoCancel() + { + iProperty.Cancel(); + iNotifierArray.ResetAndDestroy(); + } + +TInt CSifOperationsNotifier::RunError(TInt aError) + { + DEBUG_PRINTF2(_L8("CSifOperationsNotifier::RunError : Error code %d"), aError); + // If RunL() leaves due to ActiveOperationsNotificationL(), change the state. + if(iNotifierState == EFirstStart) + { + iNotifierState = EWaitForChange; + } + (void)aError; + return KErrNone; + } + + +CSifOperationsNotifier::~CSifOperationsNotifier() + { + Cancel(); + iProperty.Close(); + iKeyArray.Close(); + } + + + +////////////////////////// +// CSifNotifierBase +////////////////////////// + + +EXPORT_C CSifNotifierBase* CSifNotifierBase::NewL(MSifOperationsHandler& aHandler, TUint aKey, TNotifierType aType) + { + CSifNotifierBase* self = CSifNotifierBase::NewLC(aHandler, aKey, aType); + CleanupStack::Pop(self); + return self; + } + + +EXPORT_C CSifNotifierBase* CSifNotifierBase::NewLC(MSifOperationsHandler& aHandler, TUint aKey, TNotifierType aType) + { + CSifNotifierBase* self = new (ELeave) CSifNotifierBase(aHandler, aKey, aType); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +CSifNotifierBase::CSifNotifierBase(MSifOperationsHandler& aHandler, TUint aKey, TNotifierType aType): + CActive(EPriorityNormal), + iHandler(aHandler), + iKey(aKey), + iBufferSize(KBufferSize), + iType(aType) + { + //Empty + } + + +void CSifNotifierBase::ConstructL() + { + CActiveScheduler::Add(this); + iProperty.Attach(KUidSystemCategory,iKey,EOwnerThread); + // Subscribe to the key and wait for a notification. + WaitForChangeL(); + } + + +void CSifNotifierBase::RunL() + { + User::LeaveIfError(iStatus.Int()); + + //Resubscribe for any changes. + WaitForChangeL(); + + RBuf8 externalizedBuffer; + GetDataL(iKey, iBufferSize, externalizedBuffer); + externalizedBuffer.CleanupClosePushL(); + + RDesReadStream stream(externalizedBuffer); + CleanupClosePushL(stream); + + switch (iType) + { + case EStartEndNotifier: + { + //Read the first 4 bytes + TSifOperation opType = static_cast(stream.ReadInt32L()); + stream.Release(); + stream.Open(externalizedBuffer); + switch(opType) + { + case ESifOperationEnd: + { + CSifOperationEndData* endData = CSifOperationEndData::NewL(stream); + CleanupStack::PushL(endData); + iHandler.EndOperationHandler(*endData); + CleanupStack::PopAndDestroy(endData); + break; + } + + default: + // Cannot receive a start notification here ! + User::Leave(KErrNotSupported); + break; + } + } + + break; + + case EProgressNotifier: + { + CSifOperationProgressData* progressData = CSifOperationProgressData::NewL(stream); + CleanupStack::PushL(progressData); + iHandler.ProgressOperationHandler(*progressData); + CleanupStack::PopAndDestroy(progressData); + } + } + + + CleanupStack::PopAndDestroy(2, &externalizedBuffer); + } + + + +void CSifNotifierBase::WaitForChangeL() + { + iProperty.Subscribe(iStatus); + SetActive(); + } + + +TInt CSifNotifierBase::RunError(TInt aError) + { + DEBUG_PRINTF2(_L8("CSifNotifierBase::RunError : Error code %d"), aError); + (void)aError; + return KErrNone; + } + +TUint CSifNotifierBase::Key() + { + return iKey; + } + +void CSifNotifierBase::DoCancel() + { + iProperty.Cancel(); + } + + +CSifNotifierBase::~CSifNotifierBase() + { + Cancel(); + } + + + +///////////////////// +// CSifOperationKey +///////////////////// + +CSifOperationKey::CSifOperationKey() + { + // empty + } + +CSifOperationKey::~CSifOperationKey() + { + iStartEndKeyArray.Close(); + } + +EXPORT_C CSifOperationKey* CSifOperationKey::NewL() + { + CSifOperationKey *self = CSifOperationKey::NewLC(); + CleanupStack::Pop(self); + return self; + } + +CSifOperationKey* CSifOperationKey::NewLC() + { + CSifOperationKey *self = new(ELeave) CSifOperationKey(); + CleanupStack::PushL(self); + return self; + } + +CSifOperationKey* CSifOperationKey::NewL(RReadStream& aStream) + { + CSifOperationKey *self = new(ELeave) CSifOperationKey(); + CleanupStack::PushL(self); + self->InternalizeL(aStream); + CleanupStack::Pop(self); + return self; + } + +EXPORT_C void CSifOperationKey::ExternalizeL(RWriteStream& aStream) const + { + TInt count = iStartEndKeyArray.Count(); + aStream.WriteUint32L(count); + for(TInt i=0 ; i< count; ++i) + { + aStream.WriteUint32L(iStartEndKeyArray[i]); + } + } + +void CSifOperationKey::InternalizeL(RReadStream& aStream) + { + TInt count = aStream.ReadUint32L(); + for(TInt i=0 ; i< count; ++i) + { + iStartEndKeyArray.AppendL(aStream.ReadUint32L()); + } + } + +const RArray& CSifOperationKey::StartEndKeys() const + { + return iStartEndKeyArray; + } + +void CSifOperationKey::AddKeyL(TUint aKey) + { + iStartEndKeyArray.AppendL(aKey); + } + +void CSifOperationKey::DeleteKey(TUint aPos) + { + iStartEndKeyArray.Remove(aPos); + } + + +///////////////////// +// CDeleteKeyTimer +///////////////////// + + +CDeleteKeyTimer::CDeleteKeyTimer() : CTimer(EPriorityLow) + { + CActiveScheduler::Add(this); + } + +CDeleteKeyTimer::~CDeleteKeyTimer() + { + Cancel(); + } + +CDeleteKeyTimer* CDeleteKeyTimer::NewL(const TUint aKey) + { + CDeleteKeyTimer* self = new(ELeave) CDeleteKeyTimer(); + CleanupStack::PushL(self); + self->ConstructL(aKey); + CleanupStack::Pop(self); + return self; + } + +void CDeleteKeyTimer::ConstructL(const TUint aKey) + { + CTimer::ConstructL(); + iKey = aKey; + } + +void CDeleteKeyTimer::Start() + { + After(KDeleteKeyDelay); + } + +void CDeleteKeyTimer::RunL() + { + // Publish(remove this key from existing info) the remaining keys in the global SIF key. + TBuf8 buf; + RProperty oprnProperty; + CleanupClosePushL(oprnProperty); + + oprnProperty.Attach(KUidSystemCategory, KSifOperationKey); + TInt err = oprnProperty.Get(buf); + User::LeaveIfError(err); + + RDesReadStream readStream(buf); + CleanupClosePushL(readStream); + CSifOperationKey* opKey = CSifOperationKey::NewL(readStream); + CleanupStack::PushL(opKey); + + //Find the position of the key + TInt pos = opKey->StartEndKeys().Find(iKey); + + // Delete key, externalize the updated CSifOperationKey object and publish it. + opKey->DeleteKey(pos); + + RBuf8 operationKeyData; + operationKeyData.CleanupClosePushL(); + ExternalizeRefObjectL(*opKey, operationKeyData); + + User::LeaveIfError(oprnProperty.Set(operationKeyData)); + + // StartEnd Key. + RProperty::Delete(KUidSystemCategory, iKey); + // Progress Key. + RProperty::Delete(KUidSystemCategory, (iKey+1)); + + CleanupStack::PopAndDestroy(4, &oprnProperty); + } + + +TInt CDeleteKeyTimer::RunError(TInt aError) + { + DEBUG_PRINTF2(_L8("CDeleteKeyTimer::RunError : Error code %d"), aError); + (void)aError; + + // StartEnd Key. + RProperty::Delete(KUidSystemCategory, iKey); + // Progress Key. + RProperty::Delete(KUidSystemCategory, (iKey+1)); + return KErrNone; + }