--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/source/swis/server/statemachine.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,432 @@
+/*
+* Copyright (c) 2004-2009 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:
+*
+*/
+
+
+#include "statemachine.h"
+#include "log.h"
+#include "plan.h"
+#include "swispubsubdefs.h"
+
+namespace Swi
+{
+
+//
+// CSwisStateMachine
+//
+
+CSwisStateMachine::CSwisStateMachine(const RMessage2& aMessage)
+: CActive(EPriorityNormal),
+ iMessage(aMessage)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+CSwisStateMachine::CSwisStateMachine(const RMessage2& aMessage,TBool aInInfoMode)
+: CActive(EPriorityNormal),
+ iMessage(aMessage)
+ {
+ CActiveScheduler::Add(this);
+ // Set the state machine to operate on component information extraction mode
+ // (simply extract and return the info don't install the component).
+ iIsInInfoMode = aInInfoMode;
+ }
+#endif
+
+CSwisStateMachine::~CSwisStateMachine()
+ {
+ Cancel();
+ // close UISS session
+ iUiHandler.Close();
+
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ iStsSession.Close();
+ delete iRegistryWrapper;
+ delete iProgressPublisher;
+#else
+ delete iIntegrityServices;
+#endif
+
+ // close SWI Observer session
+ iObserver.Close();
+ }
+
+void CSwisStateMachine::ConstructL()
+ {
+ // mark the installation/un-installation operation as unconfirmed to start with
+ iOperationConfirmed = EFalse;
+
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ iStsSession.CreateTransactionL();
+ iRegistryWrapper = CRegistryWrapper::NewL();
+ iProgressPublisher = CProgressBarValuePublisher::NewL();
+ iUiHandler.SetProgressBarValuePublisher(iProgressPublisher);
+#else
+ // Create integrity services, use the current time as transaction ID
+ TTime currentTime;
+ currentTime.UniversalTime();
+ _LIT(KIntegrityServicesPath, "\\sys\\install\\integrityservices\\");
+ iIntegrityServices=CIntegrityServices::NewL(currentTime.Int64(),
+ KIntegrityServicesPath);
+ // attempt to recover any previously failed installations
+ // do not let failed rollback prevent this installation from taking place
+ TRAP_IGNORE(iIntegrityServices->RollBackL(ETrue));
+ if (iIntegrityServices->StartedJournalRollback())
+ {
+ // At least one journal file started being rolled back. In case any
+ // registry entries were removed, the cache must be regenerated.
+ ResetRegistryCache();
+ }
+#endif
+ }
+
+TInt CSwisStateMachine::Start()
+ {
+ // connect to the UISS
+ TInt err=iUiHandler.Connect();
+ if (err!=KErrNone)
+ {
+ return err;
+ }
+ // kick off
+ CompleteSelf();
+ SetActive();
+ return KErrNone;
+ }
+
+void CSwisStateMachine::CompleteSelf()
+ {
+ TRequestStatus* status=&iStatus;
+ User::RequestComplete(status, KErrNone);
+ }
+
+void CSwisStateMachine::ChangeStateL(TState* aNextState)
+ {
+ // Enter aNextState and make it our current state
+ TInt err=KErrNone;
+ while (aNextState)
+ {
+ // State change required
+ iState=aNextState;
+ TRAP(err, iState->EnterL());
+ aNextState=err ? ErrorOnStateEntryL(err) : NULL;
+ }
+
+ if (err!=KErrNone && aNextState==NULL)
+ {
+ // There was an error and we couldn't recover from it so leave with the error
+ User::Leave(err);
+ }
+ }
+
+void CSwisStateMachine::RunL()
+ {
+ if (iCancelled)
+ {
+ FinalizeJournalsL(KErrCancel);
+ PostJournalFinalizationL(KErrCancel);
+ CompleteClientL(KErrCancel);
+ return;
+ }
+
+ if (iState==NULL)
+ {
+ ChangeStateL(FirstState());
+ }
+ else
+ {
+ // See how the last SetActive() ended up
+ TInt err=iStatus.Int();
+ // Decide what to do next
+ TState* nextState=NULL;
+ if (err==KErrNone)
+ {
+ // Everything was OK, leave this state
+ nextState=iState->CompleteL();
+ }
+ else
+ {
+ // Something went wrong
+ nextState=iState->ErrorL(err);
+ }
+
+ // Move on to the next state (could be NULL, in which case we're done)
+ ChangeStateL(nextState);
+
+ if (nextState==NULL)
+ {
+ FinalizeJournalsL(KErrNone);
+ PostJournalFinalizationL(KErrNone);
+ CompleteClientL(KErrNone);
+ }
+ }
+ }
+
+void CSwisStateMachine::PostJournalFinalizationL(TInt /*aError*/ )
+ {
+
+ }
+
+void CSwisStateMachine::CompleteClientL(TInt aError)
+ {
+ DEBUG_PRINTF2(_L8("Completing Install/Uninstall client with code '%d'"), aError);
+ iMessage.Complete(aError);
+ }
+
+/**
+ * If there is no error signals the client that the (un)install has finished before
+ * commiting the journals and kicking off the observer.
+ * If there is an error the journals are rolled back.
+ */
+void CSwisStateMachine::FinalizeJournalsL(TInt aError)
+ {
+ if(aError == KErrNone)
+ {
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // When the state machine runs in non info collection (ie,. installation / uninstallation) mode,
+ // We should signal the client before committing the transactions, as the client can still
+ // abort the operation at the callback.
+ if (!IsInInfoMode())
+ {
+ SignalCompletedL();
+
+ // NOTE: There is a caveat here as we need to commit two independant transactions and there
+ // exists a possibility that the second commit fails and this would leave the device in an
+ // inconsistent state - there is no known solution for this
+ // Due to the fact that SCR allows only one transaction at a time (one writer, many readers),
+ // the possibility of the registry commit (SCR commit) failing is less likely than an STS commit
+ // failure - therefore we commit STS first and then the registry
+ iStsSession.CommitL();
+ iRegistryWrapper->CommitMutableOperationsL();
+ //If the operation is successfull, call Commit of the SWI Observer.
+ //Otherwise, do not commit to allow SWI Observer to delete the observation file.
+ iObserver.CommitL();
+ }
+ else
+ {
+ // We are runing in information collection mode. So, simply ignore the transaction details.
+ // Close SWI Observer session to release the observation log file handle.
+ // Otherwise, the rollback would not be able to delete the swi observer log file.
+ iObserver.Close();
+ iStsSession.RollBackL();
+ iRegistryWrapper->RollbackMutableOperationsL();
+ }
+ #else
+ SignalCompletedL();
+ iIntegrityServices->CommitL();
+ //If the operation is successfull, call Commit of the SWI Observer.
+ //Otherwise, do not commit to allow SWI Observer to delete the observation file.
+ iObserver.CommitL();
+ #endif
+ }
+ else
+ {
+ #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // Close SWI Observer session to release the observation log file handle.
+ // Otherwise, the rollback would not be able to delete the swi observer log file.
+ iObserver.Close();
+ iStsSession.RollBackL();
+ iRegistryWrapper->RollbackMutableOperationsL();
+ #else
+ // Close SWI Observer session to release the observation log file handle.
+ // Otherwise, the rollback would not be able to delete the swi observer log file.
+ iObserver.Close();
+ iIntegrityServices->RollBackL(EFalse);
+ ResetRegistryCache();
+ #endif
+ }
+ }
+
+// Inform the user of a fatal error.
+void CSwisStateMachine::InformUserOfFatalErrorL(TInt aError)
+ {
+ // Try to inform the user
+ TAppInfo appInfo(KNullDesC, KNullDesC, TVersion());
+ switch (aError)
+ {
+ // We can get "file corrupt" error when
+ // getting the controller, at which point the planner is not yet
+ // available.
+ case KErrCorrupt: // file corrupt
+ {
+ CDisplayError* cmd=CDisplayError::NewLC(appInfo, EUiFileCorrupt,
+ KNullDesC);
+ iUiHandler.ExecuteL(*cmd);
+ CleanupStack::PopAndDestroy(cmd);
+ break;
+ }
+
+ // If the disk is not ready on reading controller or logo, etc.
+ // then handle this with a disk not present error note
+ case KErrNotReady:
+ {
+ CDisplayError* event=CDisplayError::NewLC(appInfo, EUiDiskNotPresent, KNullDesC);
+ iUiHandler.ExecuteL(*event);
+ CleanupStack::PopAndDestroy(event);
+ break;
+ }
+
+ case KErrDiskFull:
+ {
+ CDisplayError* event=CDisplayError::NewLC(appInfo, EUiInsufficientSpaceOnDrive, KNullDesC);
+ iUiHandler.ExecuteL(*event);
+ CleanupStack::PopAndDestroy(event);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ iStsSession.RollBackL();
+ iRegistryWrapper->RollbackMutableOperationsL();
+#else
+ iIntegrityServices->RollBackL(EFalse);
+#endif
+ }
+
+#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+void CSwisStateMachine::ResetRegistryCache(void)
+ {
+ // Need to get the registry to reload its cache since we may have deleted
+ // files which were in it.
+ // Nothing we can do about errors during rollback here
+ RSisRegistryWritableSession session;
+ if (KErrNone==session.Connect())
+ {
+ TRAP_IGNORE(session.RegenerateCacheL());
+ session.Close();
+ }
+ }
+#endif
+
+// This is called if RunL() leaves.
+TInt CSwisStateMachine::RunError(TInt aError)
+ {
+ DEBUG_PRINTF2(_L8("Install/Uninstall Statemachine RunL() leave with code '%d'"), aError);
+
+ TInt property = 0;
+ if (RProperty::Get(KUidSystemCategory, KUidSoftwareInstallKey, property) == KErrNone)
+ {
+ RProperty::Set(KUidSystemCategory, KUidSoftwareInstallKey, property | ESwisStatusAborted);
+ }
+ // Close SWI Observer session to release the observation log file handle.
+ // Otherwise, the rollback would not be able to delete the swi observer log file.
+ iObserver.Close();
+
+ // RunError cannot leave so ignore UI problems when attempting
+ // to display fatal error messages.
+ TRAPD(err, InformUserOfFatalErrorL(aError));
+ if(err != KErrNone)
+ {
+ // Dialog failed so use its error code instead?!
+ aError = err;
+ }
+
+#ifndef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+ // don't want to regenerate the sisregistry if the user has declined the install/un-install
+ // and the registry has not been altered, as this makes the UI unresponsive.
+ if (iOperationConfirmed)
+ {
+ // re-generate the sisregistry cache .. very time consuming!
+ ResetRegistryCache();
+ }
+#endif
+
+ iMessage.Complete(aError);
+ return KErrNone;
+ }
+
+void CSwisStateMachine::DoCancel()
+ {
+ }
+
+// called when an install is cancelled whilst files are being copied
+void CSwisStateMachine::CancelInstallation()
+ {
+ DEBUG_PRINTF(_L8("Install/Uninstall cancelled"));
+
+ if (!iCancelled)
+ {
+ iCancelled=ETrue;
+ if(iState)
+ {
+ // cancel install
+ iState->Cancel();
+ }
+ }
+ }
+
+void CSwisStateMachine::SetNextState(TState* aState)
+ {
+ iState=aState;
+ }
+
+void CSwisStateMachine::HandleInstallationEventL(CPlan* plan, TInstallEvent aEvent, TInt aValue)
+ {
+ TInt err=KErrGeneral;
+ if (plan)
+ {
+ TRAP(err, plan->AppInfoL());
+ }
+
+ if (err==KErrNone)
+ {
+ CHandleInstallEvent* cmd = CHandleInstallEvent::NewLC(plan->AppInfoL(), aEvent, aValue, KNullDesC);
+ UiHandler().ExecuteL(*cmd);
+
+ if (!cmd->ReturnResult())
+ {
+ User::Leave(KErrCancel);
+ }
+
+ CleanupStack::PopAndDestroy(cmd);
+ }
+ else
+ {
+ TAppInfo appInfo(KNullDesC, KNullDesC, TVersion());
+ CHandleInstallEvent* cmd = CHandleInstallEvent::NewLC(appInfo, aEvent, aValue, KNullDesC);
+ UiHandler().ExecuteL(*cmd);
+
+ if (!cmd->ReturnResult())
+ {
+ User::Leave(KErrCancel);
+ }
+
+ CleanupStack::PopAndDestroy(cmd);
+ }
+ }
+
+#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
+TBool CSwisStateMachine::IsInInfoMode()
+ {
+ return iIsInInfoMode;
+ }
+
+void CSwisStateMachine::SetIsInInfoMode(TBool aOperationalMode)
+ {
+ iIsInInfoMode = aOperationalMode;
+ }
+
+void CSwisStateMachine::SetFinalProgressBarValue(TInt aValue)
+ {
+ iProgressPublisher->SetFinalProgressBarValue(aValue);
+ }
+#endif
+} // namespace Swi