appinstaller/AppinstUi/Daemon/Src/versionRevisor.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:51:10 +0200
changeset 0 ba25891c3a9e
child 25 7333d7932ef7
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2004 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: 
*
*/

#include <sysutil.h>
#include <f32file.h>

#include "sisregistrysession.h"
#include "sisregistryentry.h"
#include "sisregistrypackage.h"
#include "filesisdataprovider.h"
#include "siscontroller.h"
#include "sisinfo.h"
#include "sisuid.h"
#include "sisversion.h"

#include "versionRevisor.h"
#include "uninstaller.h"
#include "SWInstDebug.h"

_LIT( KVerRevStubSISDir, "z:\\system\\install\\" );
_LIT( KVerRevVersionFile, "c:\\private\\10202DCE\\firmware_version.txt" );
_LIT( KVerRevPrivatePath, "c:\\private\\10202DCE\\" );
_LIT( KVerRevNewLinePattern, "\\n" );
_LIT( KVerRevNewLine, "\n" );
_LIT( KVerRevSysPath, "\\sys\\bin\\" );
_LIT( KVerRevRomSysPath, "z:\\sys\\bin\\" );
const TInt KVerRevStrLength = KSysUtilVersionTextLength;  
const TUint KVerRevDriveC = 4; //0x04 = C drive.

const TInt KVerRevSisVersionOlder = 200;
const TInt KVerRevSisVersionSame = 300;
const TInt KVerRevSisVersionNewer = 400;

namespace Swi
    {
    // -----------------------------------------------------------------------
    // Two-phased constructor
    // -----------------------------------------------------------------------
    //    
    CVersionRevisor* CVersionRevisor::NewL( CProgramStatus& aMainStatus )
        {
        CVersionRevisor* self = NewLC( aMainStatus );
        CleanupStack::Pop( self );
        return self;
        }
    
    // ------------------------------------------------------------------------
    // Two-phased constructor
    // ------------------------------------------------------------------------
    //    
    CVersionRevisor* CVersionRevisor::NewLC( CProgramStatus& aMainStatus )
        {
        CVersionRevisor* self = new (ELeave) CVersionRevisor;
        CleanupStack::PushL( self );
        self->ConstructL( aMainStatus );
        return self;    
        }
      
    // -----------------------------------------------------------------------
    // 2nd constructor
    // -----------------------------------------------------------------------
    //    
    void CVersionRevisor::ConstructL( CProgramStatus& aMainStatus )
        {
        FLOG( _L("[VersionRev] ConstructL start") );
        iSisUninstaller = NULL;
        iStartupReason = KErrNone; 
        // Note revisor do not own this instance.
        iProgramStatus = &aMainStatus;         
        User::LeaveIfError( iFs.Connect() );
        // Get system startup reason.
        TRAP_IGNORE( StartUpReasonL() );         
        FLOG( _L("[VersionRev] ConstructL end") );
        }
    
    // -----------------------------------------------------------------------
    // c++ destructor
    // -----------------------------------------------------------------------
    //    
    CVersionRevisor::~CVersionRevisor()
        {
        FLOG( _L("[VersionRev] ~CVersionRevisor start") );         
        delete iSisUninstaller;
        iSisUninstaller = NULL;         
        iStubDataArray.ResetAndDestroy();               
        iFs.Close(); 
        FLOG( _L("[VersionRev] ~CVersionRevisor end") ); 
        }
     
    // -----------------------------------------------------------------------
    // Starts uninstall process.
    // -----------------------------------------------------------------------
    //    
    TInt CVersionRevisor::StartProcessL()
        {  
        FLOG( _L("[VersionRev] StartProcessL start") );        
        TInt err = KErrNone;
        
        // If firmware update is done, start scan process.
         if( iStartupReason == EFirmwareUpdate )
              {                             
              iSisUninstaller = 
                  CSisPkgUninstaller::NewL( *iProgramStatus, *this );  
              
              TRAP( err, ProcessStubFilesL() );
              FLOG_1( _L("[VersionRev] Process stub TRAP error = %d"), err );
               
              TRAP( err, ProcessSisRegistryL() ); 
              FLOG_1( _L("[VersionRev] Process sis TRAP error = %d"), err );
               
              iSisUninstaller->StartUninstallL();                           
              }        
         else
             {
             FLOG( _L("[VersionRev] StartProcessL: No firmware update") );
             // Ok, no need to start process. Leave so main will call delete. 
             User::Leave( KErrAbort );
             }
                                                     
        FLOG( _L("[VersionRev] StartProcessL end") );
        return KErrNone;
        }
   
    // -----------------------------------------------------------------------
    // Reads stub sis files.
    // -----------------------------------------------------------------------
    //    
    TInt CVersionRevisor::ProcessStubFilesL()
        {  
        FLOG( _L("[VersionRev] ProcessStubFilesL start") );
        CDir* dir;
        
        TInt err = iFs.GetDir( 
                KVerRevStubSISDir, 
                KEntryAttNormal, 
                ESortNone, 
                dir );
        
        if ( err == KErrNone )
            {
            CleanupStack::PushL( dir );
            
            TInt count = dir->Count();
            FLOG_1( _L("[VersionRev] Stub count = %d"), count );

            for ( TInt index = 0; index < count; index++ )
                {
                FLOG_1( _L("[VersionRev] Stub index = %d"), index );                                               
                TFileName stubName;                 
                stubName.Append( KVerRevStubSISDir );
                stubName.Append( (*dir)[index].iName );                
                FLOG_1( _L("[VersionRev] Stub name: %S\n "), 
                        &(*dir)[index].iName );                
                // Function needs to be trapped because SisController leavs 
                // if some corrupted file is in dir etc.
                TRAP( err, AppendStubInfoL( stubName ) );                            
                }                       
            CleanupStack::PopAndDestroy( dir ); 
            }
        
        FLOG( _L("[VersionRev] ProcessStubFilesL end") );         
        return err;
        }
    
    // -----------------------------------------------------------------------
    // Checks rom updates from sis registry and adds pkg UID to array for
    // uninstaller process.
    //
    // Pre contitons for uninstall is: 
    // 1. sis version is older or same as rom STUB version.
    // 2. sis has files only in C drvie.
    // 3. if sis version is same as stub version, all binary files must be
    // present in rom (z:\sys\bin).
    // Rom STUB <- SA       = uninstalled
    // Rom STUB <- SP       = no uninstall, returned drive is Z   (0x04)
    // Rom STUB <- PU       = no uninstall, returned drive is Z+C (0x2000004)
    // Rom STUB <- SA <- SP = SA is uninstalled, SP is not (n-gage) 
    // Rom STUB <- SA <- PU = uninstalled
    // Rom STUB <- SA + emped. sis = SA is uninstalled, empedded pkg is not.
    // -----------------------------------------------------------------------
    //    
    TInt CVersionRevisor::ProcessSisRegistryL()
        {
        FLOG( _L("[VersionRev] ProcessSisRegistryL start") );        
        TInt stubArrayCount = iStubDataArray.Count();
        FLOG_1( _L("[VersionRev] Stub array count = %d"), stubArrayCount );
        
        if ( stubArrayCount )
            {
            Swi::RSisRegistrySession sisRegSession;                                        
            User::LeaveIfError( sisRegSession.Connect() );                
            CleanupClosePushL( sisRegSession );
                               
            Swi::RSisRegistryEntry entry;                                    
            TInt err = KErrNone;
                         
            // Search correct sis pagace and open entry to it.
            for ( TInt stubIndex = 0; stubIndex < stubArrayCount; stubIndex++ )
                {                  
                TUid stubUID = iStubDataArray[stubIndex]->pkgUID;                 
                FLOG_1( _L("[VersionRev] Stub UID: 0x%x \n "), stubUID.iUid );                                                  
                                
                TBool isInstalled = sisRegSession.IsInstalledL( stubUID );
                                                                             
                if ( isInstalled )
                    {                                
                    err = entry.Open( sisRegSession, stubUID );                     
                    
                    if ( !err )
                        {
                        CleanupClosePushL( entry );                                                                                                                                                                                                                                                                                      
                                                
                        TUint drives = entry.InstalledDrivesL();
                        FLOG_1( _L("[VersionRev] Installe drive: 0x%x \n "), 
                                drives );                                                                                               
                                                
                        if ( drives == KVerRevDriveC )
                            { 
                            FLOG( _L("[VersionRev] SIS is installed to C:") );                                                        
                            FLOG( _L("[VersionRev] Check SIS version") );
                                                        
                            TVersion stubVersion(
                                    iStubDataArray[stubIndex]->major,
                                    iStubDataArray[stubIndex]->minor,
                                    iStubDataArray[stubIndex]->build );
                                                     
                            // Check sis and stub version.              
                            TInt ver = CompareVersions( 
                                   entry.VersionL(), 
                                   stubVersion ); 
                            FLOG_1( _L("[VersionRev] CompareVer.= %d "), ver );                                                                                           
                            TBool removePkg = EFalse;
                            
                            if ( ver == KVerRevSisVersionSame )
                                {
                                // If version is same check that all binary 
                                // files in rom is found. If files are missing
                                // do not remove sis pkg.
                                FLOG( _L("[VersionRev] Sis version same"));
                                removePkg = AllRomBinariesFoundL( entry );
                                }
                            if ( ver == KVerRevSisVersionOlder )
                                {
                                FLOG( _L("[VersionRev] Sis version older"));
                                removePkg = ETrue;
                                } 
                            
                            // Add uid to uninstall array if removePkg is true.
                            if ( removePkg )
                                {                                                                   
                                iSisUninstaller->AddUidToListL( stubUID );
                                FLOG_1( _L("[VersionRev] Uninst. UID:0x%x"), 
                                          stubUID.iUid );                                  
                                } 
                            }//if
                        CleanupStack::PopAndDestroy(); //entry                         
                        }//if                                                                   
                    } //if                                                                          
                } //for  
            CleanupStack::PopAndDestroy(); //sisRegSession
            } //if
          
        return KErrNone;
        }

    
    // -----------------------------------------------------------------------
    // This function reads firmware string and checks if firmware update has
    // been done. This function does create file to private directory and
    // saves current firmware version string to it.
    // -----------------------------------------------------------------------
    //    
    void CVersionRevisor::StartUpReasonL()
        {          
        FLOG( _L("[VersionRev] StartUpReasonL") );                           
        iStartupReason = KErrNotFound;                               
        HBufC* currentVersionString = HBufC::NewLC( KVerRevStrLength*2 );
        TPtr currentStringPtr = currentVersionString->Des();
        
        // Get current firmware string from sysutil. 
        // Firmware string is saved to Z:\\resource\\versions\\sw.txt
        SysUtil::GetSWVersion( currentStringPtr );
        FLOG_1( _L("[VersionRev] Firmware version = %S "), 
                &currentStringPtr );                 
        TUint result;
        // If private directory is not found create it. 
        TInt err = iFs.Att( KVerRevPrivatePath, result );
        
        if ( ! err == KErrNone && result & KEntryAttDir )
            {                 
            iFs.CreatePrivatePath( EDriveC ); 
            FLOG( _L("[VersionRev] StartUpReasonL: Create private folder") );
            }
               
        RFile file; 
        TFindFile find( iFs );                      
        // Check if version file is found in Daemon private director.
        err = find.FindByPath( KVerRevVersionFile(), &KVerRevPrivatePath() );
        FLOG_1( _L("[VersionRev] StartUpReasonL: Find file = %d"), err );  
        
        if ( err )
            {
            // If file is not found this is first boot or user memory (C:) has 
            // been formatted. No need to start version checking but let's save
            // the current firmware version to Daemon private folder.
            err = file.Create( 
                    iFs, 
                    KVerRevVersionFile, 
                    EFileWrite|EFileRead|EFileStreamText );
            
            FLOG_1( _L("[VersionRev] file create err = %d"), err ); 
            User::LeaveIfError( err );
            
            // Write current firmware version strign to file. 
            WriteFileText( file, currentStringPtr );
            
            file.Flush();
            file.Close();                        
            }
        else
            {
            
            HBufC* previousVersionString = HBufC::NewLC( KVerRevStrLength*2 );
            TPtr previousStringPtr = previousVersionString->Des();            
            
            // Open firmware version file from private directory.
            err = file.Open( 
                    iFs, 
                    KVerRevVersionFile, 
                    EFileWrite|EFileRead|EFileStreamText );
            
            FLOG_1( _L("[VersionRev] file open err = %d"), err ); 
            User::LeaveIfError( err );            
            
            // Read previous firmware string from the file. 
            ReadFileText( file, previousStringPtr );
            FLOG_1( _L("[VersionRev] Previous sw version: %S"), 
                    &previousStringPtr ); 
                        
            file.Close();
            
            if ( previousStringPtr.Length() != 0 )
                {                                                                             
                // Compare firmware strings.
                err = previousVersionString->Compare( currentStringPtr );
                FLOG_1( _L("[VersionRev] String compare = %d"), err ); 
                
                if ( err == KErrNone )
                    {  
                    // Strings are identical, no firmware update.
                    iStartupReason = KErrNone;
                    FLOG( _L("[VersionRev] iStartupReason = KErrNone") );                 
                    }
                else
                    {
                    iStartupReason = EFirmwareUpdate;
                    FLOG( _L("[VersionRev] iStartupReason = EFirmwareUpdate") );                     
                    file.Replace(                    
                        iFs, 
                        KVerRevVersionFile, 
                        EFileWrite|EFileStreamText );                                        
                    // Ok we have firmware update. Let's write new firmware 
                    // string to file and start version checking.
                    WriteFileText( file, currentStringPtr );                                                                                 
                    file.Flush();
                    file.Close();  
                    }
                }            
            CleanupStack::PopAndDestroy(); //previousVersionString  
            }                                                                   
        CleanupStack::PopAndDestroy( ); //currentVersionString                  
        }
     
    
    // -----------------------------------------------------------------------
    // Help function to read firmware version string from file.
    // -----------------------------------------------------------------------
    //  
    void CVersionRevisor::ReadFileText( RFile& aFile, TDes& aText )
        {                        
        TFileText fileText;
        fileText.Set( aFile );
        fileText.Read( aText );
         
         // Replace new-line patterns with real ones.
         TInt position = aText.Find( KVerRevNewLinePattern );
         while ( position != KErrNotFound )
             {
             // err is a position
             aText.Replace( 
                     position, 
                     KVerRevNewLinePattern().Length(), 
                     KVerRevNewLine );
             
             position = aText.Find( KVerRevNewLinePattern );
             }                        
        }

    
    // -----------------------------------------------------------------------
    // Help function to write firmware version string from file.
    // -----------------------------------------------------------------------
    //  
    void CVersionRevisor::WriteFileText( RFile& aFile, TDes& aText )
        { 
        // Replace real new-line marker with pattern. This makes 
        // reading operation easy.
        TInt position = aText.Find( KVerRevNewLine );                
        while ( position != KErrNotFound )
            {                
            aText.Replace( 
                    position, 
                    KVerRevNewLine().Length(), 
                    KVerRevNewLinePattern );
             
             position = aText.Find( KVerRevNewLine );
             }
                     
        TFileText fileText;
        fileText.Set( aFile );
        fileText.Write( aText );                       
        }
        
    
    // -----------------------------------------------------------------------
    // This function reads stub sis files version and uid and adds the info
    // in array.
    // -----------------------------------------------------------------------
    //  
    void CVersionRevisor::AppendStubInfoL( TDesC& aStubName )
        {                                             
        CFileSisDataProvider* provider = 
            CFileSisDataProvider::NewLC( iFs, aStubName );
                
        Sis::CController* stubData = Sis::CController::NewLC( *provider );
                
        const Sis::CVersion& version = stubData->Info().Version();
                
        TVersionRevStubData* stubPkg = new( ELeave ) TVersionRevStubData();
        CleanupStack::PushL( stubPkg );        
        stubPkg->pkgUID = stubData->Info().Uid().Uid();
        stubPkg->major = version.Major();
        stubPkg->minor = version.Minor();
        stubPkg->build = version.Build();
        
        iStubDataArray.AppendL( stubPkg );
        
        CleanupStack::Pop( stubPkg );
        
 #ifdef _DEBUG  
        RDebug::Print( _L("[VersionRev] Add Stub UID: 0x%x Ver: %d.%d.%d\n "),                  
                  stubData->Info().Uid().Uid(),
                  version.Major(),
                  version.Minor(),
                  version.Build() );        
 #endif
                    
        CleanupStack::PopAndDestroy( 2, provider );
        provider = NULL;
        stubData = NULL;
        stubPkg = NULL;        
        }

    // -----------------------------------------------------------------------    
    // This function compares sis and stub versions. 
    // -----------------------------------------------------------------------
    //   
    TInt CVersionRevisor::CompareVersions( 
        TVersion aSisVer, 
        TVersion aStubVer )
        { 
        FLOG( _L("[VersionRev] CompareVersions()") );
                        
        // Compare major version
        if ( aSisVer.iMajor > aStubVer.iMajor  )
            {
            FLOG( _L("[VersionRev] STUB major version older ") );
            return KVerRevSisVersionNewer;
            }
        // If same major version, check minor version.
        else if ( aSisVer.iMajor == aStubVer.iMajor )
            {                           
            if ( aSisVer.iMinor > aStubVer.iMinor )
                {
                FLOG( _L("[VersionRev] STUB minor version older ") );
                return KVerRevSisVersionNewer;
                }
            // If same minor version, check build version.
            else if ( aSisVer.iMinor == aStubVer.iMinor )
                {
                if ( aSisVer.iBuild > aStubVer.iBuild  )
                    {
                    FLOG( _L("[VersionRev] STUB build version older ") );
                    return KVerRevSisVersionNewer;                        
                    }  
                else if ( aSisVer.iBuild == aStubVer.iBuild  )
                    {
                    // Sis build version is same as stub.
                    FLOG( _L("[VersionRev] Build version same ") );
                    return KVerRevSisVersionSame;                        
                    }                                  
                else // build
                    {
                    // Sis build version is older.
                    FLOG( _L("[VersionRev] SIS build version OLDER !") );
                    return KVerRevSisVersionOlder;
                    }
                }
            else // minor
                {
                // Sis minor version is older.
                FLOG( _L("[VersionRev] SIS minor version OLDER !") );
                return KVerRevSisVersionOlder;
                }            
            }        
        else //major
            {
            // Sis major version is older.
            FLOG( _L("[VersionRev] SIS major version OLDER !") );
            return KVerRevSisVersionOlder;
            }            
        }
  
    // -----------------------------------------------------------------------    
    // This function check that all sis pkg's binary files are found from rom. 
    // -----------------------------------------------------------------------
    //     
    TBool CVersionRevisor::AllRomBinariesFoundL( Swi::RSisRegistryEntry& aEntry )
        {
        FLOG( _L("[VersionRev] AllRomBinariesFoundL") );
        TBool allBinaryFilesFound = EFalse;
        TInt err = KErrNone;
        RPointerArray<HBufC> sisFilesArray;
        RPointerArray<HBufC> binaryFilesArray;
                
        // Get installed files from this entry.
        aEntry.FilesL( sisFilesArray );
        TInt arrayCount = sisFilesArray.Count();   
        FLOG_1( _L("[VersionRev] Sis files count = %d"), arrayCount );
        
        if ( arrayCount )
            {                                                   
            for ( TInt index = 0; index < arrayCount; index++ )
                {
                // Get file path
                HBufC* tempFilePath = sisFilesArray[index]->AllocL();
                CleanupStack::PushL( tempFilePath );
                FLOG_1( _L("[VersionRev] File path: %S \n"), tempFilePath );                
                
                // Check if file is installed to sys\bin folder.
                // Search \sys\bin string from the descriptor's data.
                err = tempFilePath->Find( KVerRevSysPath );
                FLOG_1( _L("[VersionRev] Sys path found = %d"), err );
                
                if ( err != KErrNotFound )
                    {
                    // If binary file, add to array.
                    binaryFilesArray.Append( tempFilePath );
                    CleanupStack::Pop(); //tempFilePath
                    }
                else
                    {
                    // Delete temp descriptor.
                    CleanupStack::PopAndDestroy( tempFilePath );
                    tempFilePath = NULL;
                    }                
                }
            
            // Count how meny binary files are found.
            TInt binaryCount = binaryFilesArray.Count();
            FLOG_1( _L("[VersionRev] Binary files count = %d"), binaryCount );
            if ( binaryCount )
                {
                TInt foundInRomCount = 0;
                TFindFile find( iFs );
                TParse stringParser;                
                TFileName binaryFileNameAndExt;
                
                for ( TInt index = 0; index < binaryCount; index++ )
                     {
                     // Get binary file path.
                     HBufC* binaryPathBuf = binaryFilesArray[index];
                     // Parse file name and extension.                                                  
                     stringParser.Set( *binaryPathBuf ,NULL, NULL );                                                                                  
                     binaryFileNameAndExt.Copy( stringParser.NameAndExt() );                                          
                     FLOG_1( _L("[VersionRev] Search file: %S \n"), 
                             &binaryFileNameAndExt );   
                                                             
                     // Search file in z:\sys\bin.
                     // Note path must contain drive letter.
                     err = find.FindByPath( 
                             binaryFileNameAndExt, 
                             &KVerRevRomSysPath() ); 
                     FLOG_1( _L("[VersionRev] Found in rom = %d"), err );
                     
                     if ( err == KErrNone )
                         {
                         // File found in rom. Increase counter.
                         foundInRomCount++;
                         }                                                  
                     } //for
                
                // Check that all binary files are found in rom.
                if ( binaryCount == foundInRomCount )
                    {
                    allBinaryFilesFound = ETrue;
                    FLOG( _L("[VersionRev] All rom file found !") );
                    }                
                } //if  
            
            // Free all objects and array.
            binaryFilesArray.ResetAndDestroy();
            }
        // Free all objects and array.
        sisFilesArray.ResetAndDestroy();
        
        return allBinaryFilesFound;
        }
    
    
    // -----------------------------------------------------------------------
    // This function handles VersionRevisors self exit.
    // -----------------------------------------------------------------------
    //      
     void CVersionRevisor::Exit()
         {
         FLOG( _L("[VersionRev] Exit() ") );         
         // Ok all is done. Free all resources and exit.
         delete this;
         }

    } // namespace Swi

//EOF