diff -r ac7f88fb2797 -r b3a7d8e28262 fotaapplication/fotaserver/src/FotaDB.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fotaapplication/fotaserver/src/FotaDB.cpp Thu Jul 22 16:43:13 2010 +0100 @@ -0,0 +1,549 @@ +/* + * 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 +#include "FotaDB.h" +#include "FotaSrvDebug.h" +#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) + { + } + +// --------------------------------------------------------------------------- +// 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(); + } + 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(); + + 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, TDes8& aPkgURL) + { + 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); + aPkgURL.Copy(url->Des()); + 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::Leave(KErrArgument) ); + TBuf8 temp; + TPackageState found = GetStateL(aState.iPkgId, temp); + 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<=602, User::Leave(KErrArgument) ); + sql->Des().AppendFormat(_L8("Result=%d,"), aState.iResult); + } + if (aChangedFields & EFDBState) + { + // check FUMO compability + __ASSERT_ALWAYS( aState.iState>=0 && aState.iState<=100 + , User::Leave(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::Leave(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::Leave(KErrArgument) ); + sql->Des().AppendFormat(_L8("IapId=%d,"), aState.iIapId); + } + if (aChangedFields & EFDBPkgSize) + { + 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::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); + }