brandingserver/bsclient/bsprocessstarter.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:27:45 +0100
branchRCL_3
changeset 22 113b91e0a2ad
parent 21 cfd5c2994f10
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2009 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: bsprocessstarter.cpp
*
*/
//  INCLUDE FILES
#include "bsprocessstarter.h"
#include <e32std.h>
#include <f32file.h>


// CONSTANTS
_LIT( KEka2ExeDir,"\\sys\\bin\\");
_LIT( KEka2LaunchMutexExt, "[lMtx]" );
const TInt KEka2SrvConnTries = 7;
const TInt KEka2SrvConnInitialRetryWait = 500; //MicroSeconds => 0.0005s



// ==============================================================
// ====================== HELPER CLASS ==========================
// ==============================================================

/**
 * RSessionBase accessor to give to the ProcessStarter
 * access to RSessionBase::CreateSession().
 */
class REka2SessionBaseAccessor : public RSessionBase
    {
    public: // Constructor
        inline REka2SessionBaseAccessor()
            {
            }

    public: // New functions

        /**
         * Public access to RSessionBase::CreateSession().
         */
        inline TInt CreateSession( const TDesC& aServer,
                                   const TVersion& aVersion,
                                   TInt aAsyncMessageSlots )
            {
            return RSessionBase::CreateSession( aServer,
                                                aVersion,
                                                aAsyncMessageSlots );
            }
    };





// ==============================================================
// ====================== PROCESSSTARTER ========================
// ==============================================================


// --------------------------------------------------------------
// BSProcessStarter::FullExePathForClienLocation()
// --------------------------------------------------------------
//
void BSProcessStarter::FullExePathForClienLocation(
    const TDesC& aExeName,
    TFileName& aFullExePath )
    {
    //Get drive (C:) where this client code is installed
        {
        TFileName tmp;
        Dll::FileName( tmp );
        aFullExePath.Copy( TParsePtrC( tmp ).Drive() );
        }

    //Build the rest from the exe path
    aFullExePath.Append( KEka2ExeDir );
    aFullExePath.Append( aExeName );
    }



// --------------------------------------------------------------
// BSProcessStarter::StartInstance()
// --------------------------------------------------------------
//
TInt BSProcessStarter::StartInstance(
    const TDesC& aFullExePath,
    const TDesC& aCommand,
    const TArray< TProcessStartupParam >* aParams )
    {
    RMutex launchMutex;
    TInt error = KErrNotFound;

        {
        // Dynamic mutex name used to allow code share
        TName launchMutexName( TParsePtrC( aFullExePath ).Name() );
        launchMutexName.Append( KEka2LaunchMutexExt );

        // Open or Create mutex to serialize to access to server startup code.
        // (race condition safe way)
        while( error == KErrNotFound )
            {
            error = launchMutex.CreateGlobal( launchMutexName );
            if( error != KErrAlreadyExists )
                {
                break;
                }
            error = launchMutex.OpenGlobal( launchMutexName );
            }

        if( error != KErrNone )
            {
            return error;
            }
        }


    launchMutex.Wait();

    //Serialized access
    error = BSProcessStarter::DoStartInstance( aFullExePath,
                                             aCommand,
                                             aParams );

    launchMutex.Signal();
    launchMutex.Close();

    return error;
    }



// --------------------------------------------------------------
// BSProcessStarter::ConnectToServer()
// --------------------------------------------------------------
//
TInt BSProcessStarter::ConnectToServer(
    const TDesC& aFullExePath,
    const TDesC& aCommand,
    const TArray< TProcessStartupParam >* aParams,
    RSessionBase& aSessionToConnect,
    const TDesC& aServerName,
    const TVersion& aClientVersion,
    TInt aAsyncMessageSlots )
    {
    if( aSessionToConnect.Handle() != KNullHandle )
        {
        return KErrInUse;
        }

    TInt err = KErrNone;
    TInt startupWait = KEka2SrvConnInitialRetryWait;

    //Server connect and launch loop
    for( TInt trie = 0 ; trie < KEka2SrvConnTries ; trie++ )
        {
        REka2SessionBaseAccessor acc;
        err = acc.CreateSession( aServerName,
                                 aClientVersion,
                                 aAsyncMessageSlots );

        if( err == KErrNone )
            {
            //session ownership is now on client
            aSessionToConnect = acc;
            return KErrNone;
            }

        else if( ( err == KErrNotFound ) ||
                 ( err == KErrServerTerminated ) )
            {
            //Server missing or died when connecting
            //Start a new server
            err = BSProcessStarter::StartInstance( aFullExePath,
                                                 aCommand,
                                                 aParams );

            //If process exist already, then all is fine
            //(some other process started it between the origical connect and launch trie)
            if( err == KErrAlreadyExists )
                {
                err = KErrNone;
                }

            //If server process start failed, bail out.
            if( err != KErrNone )
                {
                return err;
                }

            //If this is 2nd or subsequent try,
            //give some time for server to startup
            if( trie > 0 )
                {
                // Code scanner warning : Use of User::After (id:92)
                // it is required to be used here
                User::After( startupWait ); // CSI: 92 # See above
                startupWait = 2 * startupWait;
                }
            }

        else
            {
            //Server process start failed. Bail out.
            return err;
            }
        }

    return err;
    }



// --------------------------------------------------------------
// BSProcessStarter::DoStartServerInstance()
// --------------------------------------------------------------
//
TInt BSProcessStarter::DoStartInstance(
    const TDesC& aFullExePath,
    const TDesC& aCommand,
    const TArray< TProcessStartupParam >* aParams )
    {
    TInt error = KErrNone;

    //Create process
    RProcess process;
    error = process.Create( aFullExePath, aCommand );

    if( error == KErrNone )
        {
        //Set process startup parameters
        error = ApplyParameters( aParams, process );

        //And execute the process and wait it's startup
       if( error == KErrNone )
            {
            TRequestStatus rendezvousStatus;
            process.Rendezvous( rendezvousStatus );

            process.Resume();
            // Codescanner warning: user of User::WaitForRequest (Id:94)
            // it is required to use at server startup
            User::WaitForRequest( rendezvousStatus ); // CSI: 94 # See above
            error = rendezvousStatus.Int();

            if( process.ExitType() != EExitPending )
                {
                //Something failed in server startup
                //Force the error code to be always something
                //else than KErrNone
                if( error == KErrNone )
                    {
                    error = KErrServerTerminated;
                    }
                }
            }
        }

    process.Close();

    return error;
    }



// --------------------------------------------------------------
// BSProcessStarter::ApplyParameters()
// --------------------------------------------------------------
//
TInt BSProcessStarter::ApplyParameters(
    const TArray< TProcessStartupParam >* aParams,
    RProcess& aProcess )
    {
    TInt error = KErrNone;
    if( aParams )
        {
        const TInt paramCount = aParams->Count();
        for( TInt ix = 0; ix < paramCount; ix++ )
            {
            error = (*aParams)[ ix ].ApplyParam( aProcess );
            if( error != KErrNone )
                {
                break;
                }
            }
        }

    return error;
    }



// ==============================================================
// ================== TPROCESSSTARTUPPARAM ======================
// ==============================================================

// --------------------------------------------------------------
// TProcessStartupParam::TProcessStartupParam()
// --------------------------------------------------------------
//
TProcessStartupParam::TProcessStartupParam()
    : iType( EUnknown ),
      iSlot( KErrNotFound )
    {
    }


// --------------------------------------------------------------
// TProcessStartupParam::Set()
// --------------------------------------------------------------
//
void TProcessStartupParam::Set( TInt aSlot,
                                const RHandleBase& aHandle )
    {
    iType = EHandle;
    iSlot = aSlot;
    iHandle = &aHandle;
    }


// --------------------------------------------------------------
// TProcessStartupParam::Set()
// --------------------------------------------------------------
//
void TProcessStartupParam::Set( TInt aSlot,
                                const RSubSessionBase& aSubSession )
    {
    iType = ESubSession;
    iSlot = aSlot;
    iSubSession = &aSubSession;
    }


// --------------------------------------------------------------
// TProcessStartupParam::Set()
// --------------------------------------------------------------
//
void TProcessStartupParam::Set( TInt aSlot,
                                const TDesC16& aDes )
    {
    iType = EDes16;
    iSlot = aSlot;
    iDes16.Set( aDes );
    }


// --------------------------------------------------------------
// TProcessStartupParam::Set()
// --------------------------------------------------------------
//
void TProcessStartupParam::Set( TInt aSlot,
                                const TDesC8& aDes )
    {
    iType = EDes8;
    iSlot = aSlot;
    iDes8.Set( aDes );
    }


// --------------------------------------------------------------
// TProcessStartupParam::Set()
// --------------------------------------------------------------
//
void TProcessStartupParam::Set( TInt aSlot,
                                TInt aInt )
    {
    iType = EInt;
    iSlot = aSlot;
    iInt = aInt;
    }


// --------------------------------------------------------------
// TProcessStartupParam::ApplyParam()
// --------------------------------------------------------------
//
TInt TProcessStartupParam::ApplyParam( RProcess& aProcess ) const
    {
    switch( iType )
        {
        case EHandle: return aProcess.SetParameter( iSlot, *iHandle );
        case ESubSession: return aProcess.SetParameter( iSlot, *iSubSession );
        case EDes16: return aProcess.SetParameter( iSlot, iDes16 );
        case EDes8: return aProcess.SetParameter( iSlot, iDes8 );
        case EInt: return aProcess.SetParameter( iSlot, iInt );
        }

    return KErrUnknown;
    }


// END OF FILE