diff -r 000000000000 -r b497e44ab2fc fotaapplication/fotaserver/FotaServer/src/FotaDB.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fotaapplication/fotaserver/FotaServer/src/FotaDB.cpp Thu Dec 17 09:07:52 2009 +0200 @@ -0,0 +1,640 @@ +/* +* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: Fota package state preservation +* +*/ + + + +#include "FotaDB.h" +#include "FotaSrvDebug.h" +#include +#include "fotaserverPrivateCRKeys.h" + +#define __LEAVE_IF_ERROR(x) if(KErrNone!=x) {FLOG(_L("LEAVE in %s: %d"), __FILE__, __LINE__); User::Leave(x); } + +// ====================== MEMBER FUNCTIONS =================================== + +// --------------------------------------------------------------------------- +// CFotaDB::CFotaDB() +// --------------------------------------------------------------------------- +CFotaDB::CFotaDB() : iIsOpen( EFalse ) + ,iTableAltercheck(ETrue) + { + } + +// --------------------------------------------------------------------------- +// CFotaDB::~CFotaDB() +// --------------------------------------------------------------------------- +CFotaDB::~CFotaDB() + { + //Delete columns set + if (iColSet) + { + delete iColSet; + iColSet = NULL; + } + //Close table + iTable.Close(); + + //Close database + iStateDB.Close(); + + //Close file server session + if (iFSSession.Handle()) + iFSSession.Close(); + } + + +// --------------------------------------------------------------------------- +// CFotaDB::NewL() +// --------------------------------------------------------------------------- +CFotaDB* CFotaDB::NewL() + { + CFotaDB* self=new(ELeave) CFotaDB(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + + +// --------------------------------------------------------------------------- +// CFotaDB::ConstructL() +// --------------------------------------------------------------------------- +void CFotaDB::ConstructL() + { + TInt err; + TBuf tmp; + User::LeaveIfError( iFSSession.Connect() ); + err = iFSSession.CreatePrivatePath( EDriveC ); + if ( err != KErrNone && err != KErrAlreadyExists ) User::Leave( err ); + User::LeaveIfError( iFSSession.SetSessionToPrivate( EDriveC ) ); + User::LeaveIfError( iFSSession.SessionPath (tmp) ); + } + + +// --------------------------------------------------------------------------- +// CFotaDB::CreateDatabaseL() +// Creates db in private dir of fotaserver +// --------------------------------------------------------------------------- +void CFotaDB::CreateDatabaseL() + { + FLOG(_L("CFotaDB::CreateDatabaseL() >>")); + TInt err; + User::LeaveIfError( iStateDB.Create( iFSSession ,KDatabaseName ) ); + User::LeaveIfError(iStateDB.Begin()); + User::LeaveIfError(iStateDB.Execute(KCreateTable)); + err = iStateDB.Commit(); + if(err) + { + FLOG(_L(" cdb err %d"),err); + iStateDB.Rollback(); + User::Leave(err); + } + User::LeaveIfError( iStateDB.Compact() ); + FLOG(_L("CFotaDB::CreateDatabaseL() <<")); + } + + +// --------------------------------------------------------------------------- +// CFotaDB::AddPackageStateL +// Adds state to db +// --------------------------------------------------------------------------- +void CFotaDB::AddPackageStateL(const TPackageState& aState + ,const TDesC8& aPkgURL) + { + FLOG(_L(" CFotaDB::AddPackageStateL >>")); + TInt err; + RDbView view; + CleanupClosePushL( view ); + TPackageState pkgstate(aState); + pkgstate.iResult = -1; // result should be -1 if no Execs have been done + err = view.Prepare( iStateDB, TDbQuery(KSelectAll), RDbView::EInsertOnly); + __LEAVE_IF_ERROR(err); + FLOG(_L(" CFotaDB::AddPackageStateL inserting. pkgid:%d result:%d \ + state:%d"), pkgstate.iPkgId,pkgstate.iResult,pkgstate.iState); + view.InsertL(); + StateToRowL( pkgstate,aPkgURL,view ); + view.PutL(); + CleanupStack::PopAndDestroy(); //view + FLOG(_L(" CFotaDB::AddPackageStateL <<")); + } + + +// --------------------------------------------------------------------------- +// CFotaDB::GetAllL +// Get all states +// --------------------------------------------------------------------------- +void CFotaDB::GetAllL( RArray& aStates) + { + RDbView view; + CleanupClosePushL( view ); + + TInt err = view.Prepare( iStateDB, TDbQuery( KSelectAll ) ); + __LEAVE_IF_ERROR(err); + view.EvaluateAll(); + + view.FirstL(); + FLOG(_L("[fota DB] --- rows --------------------------------------------\ + ----------------------- v")); + while ( view.AtRow() ) + { + view.GetL(); + HBufC8* url; + TPackageState s = RowToStateL(url,view); + aStates.Append( s.iPkgId ); + CleanupStack::PushL ( url ); + FLOG(_L("[fotaDB] pkgid: %d profid:%d state:%d result:%d \ + url: %d chars sessiontype:%d IapId:%d Pkgsize:%d UpdateLtr:%d"), s.iPkgId, s.iProfileId, s.iState,s.iResult + ,url->Des().Length(), s.iSessionType, s.iIapId, s.iPkgSize, s.iUpdateLtr ); + CleanupStack::PopAndDestroy(); // url + view.NextL(); + } + FLOG(_L("[fota DB] --- rows --------------------------------------------\ + ----------------------- ^")); + view.Close(); + CleanupStack::PopAndDestroy(); //view + } + + +// --------------------------------------------------------------------------- +// CFotaDB::OpenDBL() +// Opens database +// --------------------------------------------------------------------------- +void CFotaDB::OpenDBL() + { + FLOG(_L("CFotaDB::OpenDBL()")); + if (!iIsOpen) //Prevents accidental opening of database twice + { + TInt err; + err = iStateDB.Open ( iFSSession ,KDatabaseName); + + if ( err == KErrNotFound ) + { + CreateDatabaseL(); + iTableAltercheck = EFalse; //Table created newly, hence no alteration required. + } + else if ( err != KErrNone ) + { + FLOG(_L("[fota DB openDB]\t db open error: %d"), err); + FLOG(_L("deleting fota DB and creating it again...")); + err = iFSSession.Delete(KDatabaseName); + CreateDatabaseL(); + User::LeaveIfError(err); + } + User::LeaveIfError( iTable.Open (iStateDB, KTblState) ); + iColSet = iTable.ColSetL(); + + //Check & correct if the table has wrong attributes - this is for data compatibility + if (iTableAltercheck) + AlterTableIfRequiredL(); + + iIsOpen = ETrue; + } + } + +// --------------------------------------------------------------------------- +// CFotaDB::CloseAndCommitDB +// Closes and commits DB +// --------------------------------------------------------------------------- +void CFotaDB::CloseAndCommitDB() + { + if ( iColSet ) + { + delete iColSet; + iColSet = NULL; + } + iTable.Close(); + iStateDB.Close(); + iIsOpen = EFalse; + } + +// --------------------------------------------------------------------------- +// CFotaDB::IsOpen() +// Chekcs if db is open +// --------------------------------------------------------------------------- +TBool CFotaDB::IsOpen() + { + return iIsOpen; + } + + +// --------------------------------------------------------------------------- +// CFotaDB::GetStateL +// Gets pkg state from db +// --------------------------------------------------------------------------- +TPackageState CFotaDB::GetStateL(const TInt aPkgId) + { + RDbView view; + TPackageState s; + CleanupClosePushL( view ); + + s.iState = RFotaEngineSession::EIdle; // default state is idle + + HBufC* select = HBufC::NewLC( KSelect_where_packageid().Length() + 10); + select->Des().Format (KSelect_where_packageid, aPkgId); + + TInt err = view.Prepare( iStateDB, TDbQuery(*select) ); + __LEAVE_IF_ERROR(err); + view.EvaluateAll(); + view.FirstL(); + + while ( view.AtRow() ) + { + view.GetL(); + HBufC8* url; + s = RowToStateL( url,view ); + CleanupStack::PushL( url ); + CleanupStack::PopAndDestroy(); // url + view.NextL(); + } + CleanupStack::PopAndDestroy(); //select + CleanupStack::PopAndDestroy(); //view + return s; + } + + +// --------------------------------------------------------------------------- +// CFotaDB::SetStateL +// Writes package state to DB. +// --------------------------------------------------------------------------- +void CFotaDB::SetStateL( TPackageState& aState, const TDesC8& aPkgURL + , TUint aChangedFields ) + { + FLOG(_L(" CFotaDB::SetStateL >> id %d result %d state %d sessiontype %d iapid %d pkgsize %d updateltr %d") + ,aState.iPkgId, aState.iResult, aState.iState); + __ASSERT_ALWAYS( aChangedFields!=0, User::Panic(KFotaPanic, KErrArgument) ); + + TPackageState found = GetStateL( aState.iPkgId ); + if ( found.iPkgId == KErrNotFound ) + { + AddPackageStateL( aState, aPkgURL); + } + else + { + // sml try count must be reset, if state is set + if (aChangedFields & EFDBState ) + { + aChangedFields = aChangedFields | EFDBSmlTryCount; + SetRetryCount(aState); + } + + // Construct a SQL string for update. + // Example: UPDATE State SET Result=40,State=4 WHERE pkgID=5 + // + TInt sqlsize = 0; + _LIT8( KSqlbegin, "UPDATE State SET " ); + TBuf<21> sqlEnd; + HBufC8* sql( NULL ); + // determine characters needed + sqlsize = DetermineCharNeeded(aChangedFields,aState,aPkgURL); + sqlEnd.AppendFormat( _L(" WHERE pkgID=%d"),aState.iPkgId ); + + sql = HBufC8::NewLC( ((TDesC8)KSqlbegin).Length() + sqlsize + + sqlEnd.Length() ); + + sql->Des().Append ( KSqlbegin ); + + if (aChangedFields & EFDBResult ) + { + // check FUMO compability + __ASSERT_ALWAYS( aState.iResult>=KErrNotFound + && aState.iResult<=600, User::Panic(KFotaPanic, KErrArgument) ); + sql->Des().AppendFormat(_L8("Result=%d,"),aState.iResult); + } + if (aChangedFields & EFDBState ) + { + // check FUMO compability + __ASSERT_ALWAYS( aState.iState>=0 && aState.iState<=100 + , User::Panic(KFotaPanic, KErrArgument) ); + sql->Des().AppendFormat(_L8("State=%d,"),aState.iState); + } + if (aChangedFields & EFDBProfileId) + { + sql->Des().AppendFormat(_L8("profileid=%d,"),aState.iProfileId); + } + if (aChangedFields & EFDBPkgUrl ) + { + sql->Des().AppendFormat(_L8("pkgurl='%S',"), &aPkgURL ); + } + if (aChangedFields & EFDBPkgName ) + { + sql->Des().AppendFormat(_L8("pkgname='%S',") + ,&(aState.iPkgName)) ; + } + if (aChangedFields & EFDBVersion ) + { + sql->Des().AppendFormat(_L8("Version='%S',") + ,&(aState.iPkgVersion)); + } + if ( aChangedFields & EFDBSmlTryCount ) + { + __ASSERT_ALWAYS( aState.iSmlTryCount>=0 + , User::Panic(KFotaPanic, KErrArgument) ); + sql->Des().AppendFormat(_L8("SmlTryCount=%d,") + , aState.iSmlTryCount ); + + } + if (aChangedFields & EFDBSessionType ) + { + sql->Des().AppendFormat(_L8("SessionType=%d,"),aState.iSessionType); + } + if (aChangedFields & EFDBIapId ) + { + // validate IAP ID + __ASSERT_ALWAYS( aState.iIapId>=-1 ,User::Panic(KFotaPanic, KErrArgument) ); + sql->Des().AppendFormat(_L8("IapId=%d,"),aState.iIapId); + } + if (aChangedFields & EFDBPkgSize ) + { + // validate size + // __ASSERT_ALWAYS( aState.iPkgSize>=0 ,User::Panic(KFotaPanic, KErrArgument) ); // to remove compiler warning + sql->Des().AppendFormat(_L8("PkgSize=%d,"),aState.iPkgSize); + } + if (aChangedFields & EFDBUpdateLtr ) + { + // validate bit + sql->Des().AppendFormat(_L8("UpdateLtr=%d,"),aState.iUpdateLtr); + } + // remove trailing , + if ( aChangedFields ) + { + sql->Des().SetLength ( sql->Des().Length()-1 ); + } + sql->Des().Append ( sqlEnd ); + HBufC* sql2 = HBufC::NewLC( sql->Length() ); // to cleanupstack + sql2->Des().Copy(sql->Des()); + FLOG(_L(" sql:%S"),sql2); + + User::LeaveIfError( iStateDB.Begin() ); + User::LeaveIfError( iStateDB.Execute(*sql2) ); + User::LeaveIfError( iStateDB.Commit() ); + User::LeaveIfError( iStateDB.Compact() ); + + CleanupStack::PopAndDestroy( sql2 ); //sql2 + CleanupStack::PopAndDestroy( sql ); //sql + } + FLOG(_L(" CFotaDB::SetStateL <<")); + } + +// --------------------------------------------------------------------------- +// CFotaDB::DetermineCharNeeded +// Returns the char needed fro the query +// --------------------------------------------------------------------------- + +TInt CFotaDB::DetermineCharNeeded(TInt aChangedFields,TPackageState& aState,const TDesC8& aPkgURL) + +{ + + TInt sqlsize=0; + if (aChangedFields & EFDBResult ) sqlsize += 4 + 7 + 4; + if (aChangedFields & EFDBState ) sqlsize += 4 + 5 + 4; + if (aChangedFields & EFDBProfileId ) sqlsize += 4 + 9 + 4; + if (aChangedFields & EFDBPkgUrl ) sqlsize += aPkgURL.Length() + + 6 + 4; + if (aChangedFields & EFDBPkgName ) sqlsize += + aState.iPkgName.Length() + + 7 + 4; + if (aChangedFields & EFDBVersion ) sqlsize += + aState.iPkgVersion.Length() + + 7 + 4; + if (aChangedFields & EFDBSmlTryCount ) sqlsize += 4 + 11 + 4; + + if (aChangedFields & EFDBSessionType ) sqlsize += 4 + 11 + 4; + if (aChangedFields & EFDBIapId ) sqlsize += 4 + 5 + 4; + if (aChangedFields & EFDBPkgSize ) sqlsize += 4 + 7 + 10; + if (aChangedFields & EFDBUpdateLtr ) sqlsize += 4 + 11 + 4; + + return sqlsize; + +} + +// --------------------------------------------------------------------------- +// CFotaDB::SetRetryCount +// Sets the retry count +// --------------------------------------------------------------------------- +void CFotaDB::SetRetryCount(TPackageState& aState) +{ + CRepository* centrep( NULL); + TInt err = KErrNone; + TInt retry = 0; + + TRAP(err, centrep = CRepository::NewL( KCRUidFotaServer ) ); + if ( centrep ) + { + err = centrep->Get( KGenericAlertRetries, retry ); + delete centrep; centrep = NULL; + } + if(err == KErrNone ) + { + if(retry < 0 ) + { + aState.iSmlTryCount = KDefaultSmlTryCount; + } + else if( retry == 0 ) + { + aState.iSmlTryCount = 2 ; + } + else if (retry > KMaximumSmlTryCount ) + { + aState.iSmlTryCount = KMaximumSmlTryCount + 1; + } + else + { + aState.iSmlTryCount = retry + 1; + } + } + else + { + aState.iSmlTryCount = KDefaultSmlTryCount; + } +} + + +// --------------------------------------------------------------------------- +// CFotaDB::DeleteStateL +// Delete state +// --------------------------------------------------------------------------- +TInt CFotaDB::DeleteStateL(const TInt aPkgId) + { + FLOG(_L("[fota DB Delete]\tdeleting %d"),aPkgId); + TInt err( KErrNone ); + + if ( iStateDB.InTransaction() ) + { + return ( KErrAccessDenied ); + } + + _LIT( KSQLDeleteState,"DELETE FROM State WHERE PkgId = %d" ); + + HBufC* del = HBufC::NewLC( KSQLDeleteState().Length() + 10); + del->Des().Format (KSQLDeleteState, aPkgId); + + iStateDB.Begin(); + + err = iStateDB.Execute( *del ); + CleanupStack::PopAndDestroy( del ); + if ( err < KErrNone ) + { + iStateDB.Rollback(); + return err; + } + FLOG(_L("[fota DB Delete]\tdeleted %d"),aPkgId); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// CFotaDB::RowToStateL +// Extracts db row contents to package state object and aPkgUrl +// Returns url in aPkgURL parameter +// --------------------------------------------------------------------------- +TPackageState CFotaDB::RowToStateL(HBufC8*& aPkgUrl,const RDbView& aView) + { + TPackageState s; + TInt pkgid = aView.ColInt( iColSet->ColNo(KColPkgId) ); + TInt state = aView.ColInt( iColSet->ColNo(KColState) ); + TInt result = aView.ColInt( iColSet->ColNo(KColResult) ); + TSmlProfileId profileid(aView.ColInt( iColSet->ColNo(KColProfileId))); + TPtrC pkgname = aView.ColDes( iColSet->ColNo(KColPkgName) ); + TPtrC version = aView.ColDes( iColSet->ColNo(KColVersion) ); + TInt smltrycount + = aView.ColInt( iColSet->ColNo(KColSmlTryCount) ); + TInt sessiontype = aView.ColInt( iColSet->ColNo(KColSessionType) ); + TInt iapid = aView.ColInt( iColSet->ColNo(KColIapId) ); + TUint pkgsize = aView.ColUint( iColSet->ColNo(KColPkgSize) ); + TBool updateltr = aView.ColUint8( iColSet->ColNo(KColUpdateLtr)); + + s.iPkgId = pkgid; + s.iPkgName.Copy (pkgname); + s.iPkgVersion.Copy (version); + s.iProfileId = profileid; + s.iResult = result; + s.iState = RFotaEngineSession::TState (state); + s.iSmlTryCount = smltrycount; + s.iSessionType = sessiontype; + s.iIapId = iapid; + s.iPkgSize = pkgsize; + s.iUpdateLtr = updateltr; + + RDbColReadStream rstream; + TInt len = aView.ColLength(iColSet->ColNo(KColPkgUrl)); + rstream.OpenLC(aView,iColSet->ColNo(KColPkgUrl) ); + HBufC* pkgurl = HBufC::NewLC( len ); + TPtr ptr = pkgurl->Des(); + rstream.ReadL( ptr, len ); + + HBufC8* tmp = HBufC8::NewL( pkgurl->Des().Length() ); + tmp->Des().Copy ( pkgurl->Des() ); + aPkgUrl = tmp; + + CleanupStack::PopAndDestroy( pkgurl ); + CleanupStack::PopAndDestroy( &rstream ); + return s; + } + + +// --------------------------------------------------------------------------- +// CFotaDB::StateToRowL +// Converts state object to database row (into view object) +// --------------------------------------------------------------------------- +void CFotaDB::StateToRowL (const TPackageState& aPkg, const TDesC8& aPkgURL + ,RDbView& aView) + { + HBufC* pkgname = HBufC::NewLC(aPkg.iPkgName.Length()); + HBufC* version = HBufC::NewLC(aPkg.iPkgVersion.Length()); + + pkgname->Des().Copy(aPkg.iPkgName); + version->Des().Copy(aPkg.iPkgVersion); + + aView.SetColL( iColSet->ColNo( KColPkgId ), aPkg.iPkgId); + aView.SetColL( iColSet->ColNo( KColResult ), aPkg.iResult); + aView.SetColL( iColSet->ColNo( KColState ), aPkg.iState); + aView.SetColL( iColSet->ColNo( KColProfileId ), aPkg.iProfileId); + aView.SetColL( iColSet->ColNo( KColPkgName ), *pkgname ); + aView.SetColL( iColSet->ColNo( KColVersion ), *version ); + aView.SetColL( iColSet->ColNo( KColSmlTryCount ), aPkg.iSmlTryCount ); + aView.SetColL( iColSet->ColNo( KColSessionType ), aPkg.iSessionType ); + aView.SetColL( iColSet->ColNo( KColIapId ), aPkg.iIapId ); + aView.SetColL( iColSet->ColNo( KColPkgSize ), aPkg.iPkgSize ); + aView.SetColL( iColSet->ColNo( KColUpdateLtr ), aPkg.iUpdateLtr ); + + RDbColWriteStream wstream; + CleanupClosePushL( wstream ); + wstream.OpenL( aView,iColSet->ColNo(KColPkgUrl) ); + // Cannot write 8 bit descriptors to databae + HBufC* buf = HBufC::NewLC( aPkgURL.Length() ); + buf->Des().Copy( aPkgURL ); + wstream.WriteL( buf->Des() ); + + FLOG(_L("CFotaDB::StateToRowL id:%d result:%d state:%d profileid:%d \ + name:%d chars version: %d chars url: %d chars sessiontype:%d iapid:%d pkgsize:%d updateltr = %d") + ,aPkg.iPkgId, aPkg.iResult, aPkg.iState, aPkg.iProfileId + , pkgname->Des().Length(), version->Des().Length() + , buf->Des().Length(),aPkg.iSessionType,aPkg.iIapId,aPkg.iPkgSize, aPkg.iUpdateLtr); + + CleanupStack::PopAndDestroy( buf ); + CleanupStack::PopAndDestroy( &wstream ); + CleanupStack::PopAndDestroy( version ); + CleanupStack::PopAndDestroy( pkgname ); + } + + +// --------------------------------------------------------------------------- +// CFotaDB::AlterTableIfRequiredL() +// Adds the new attributes when fota state table is old. +// --------------------------------------------------------------------------- +void CFotaDB::AlterTableIfRequiredL() + { + FLOG(_L("CFotaDB::AlterTableIfRequired >>")); + TInt noofcol = iTable.ColCount(); + //noofcol = 9 means old database; alteration is needed + if (noofcol!=KNoOfDBFields) + { + FLOG(_L("FotaState table is incompatible; needs alteration!")); + User::LeaveIfError(iStateDB.Begin()); + + + TInt err (KErrNone); + err = iStateDB.Execute(KAlterTable); + if (!err) + { + err = iStateDB.Commit(); + if(err) + { + FLOG(_L(" FotaState table alteration err2 %d, deleting it and recreating it again"),err); + CloseAndCommitDB(); + User::LeaveIfError (iFSSession.Delete(KDatabaseName)); + } + } + else + { + FLOG(_L(" FotaState table alteration err1 %d, deleting it and recreating it again"),err); + CloseAndCommitDB(); + User::LeaveIfError (iFSSession.Delete(KDatabaseName)); + } + if (!err) + { + User::LeaveIfError( iStateDB.Compact() ); + CloseAndCommitDB(); + FLOG(_L("FotaState table altered successfully, reopening it again.")); + iTableAltercheck = EFalse; + } + OpenDBL(); + } + else + iTableAltercheck = EFalse; + + FLOG(_L("CFotaDB::AlterTableIfRequired <<")); + }