/*
* 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: HtiAppServicePlugin implementation
*
*/
// INCLUDE FILES
#include <badesca.h>
#include <f32file.h>
#include "HtiAppServicePlugin.h"
#include <HtiDispatcherInterface.h>
#include <HtiLogging.h>
// CONSTANTS
const static TUid KAppServiceUid = { 0x1020DEC7 };
//error descriptions
_LIT8( KErrDescrNoMemory, "No memory" );
_LIT8( KErrDescrInvalidCmd, "Invalid command" );
_LIT8( KErrDescrInvalidArguments, "Invalid arguments" );
_LIT8( KErrDescrFailedCreateProcess, "Failed create process" );
_LIT8( KErrDescrFailedOpenProcess, "Failed open process" );
_LIT8( KErrDescrInvalidProcessId, "Invalid process id" );
_LIT8( KErrDescrNotSupported, "Command not supported" );
_LIT( KHtiAppControlDll, "HtiAppControl.dll" );
const static TUint8 KUnicodeMask = 0x01;
const static TInt KTerminateReason = 0;
const static TInt KTUintLength = sizeof(TUint);
// MACROS
// LOCAL CONSTANTS AND MACROS
// MODULE DATA STRUCTURES
// LOCAL FUNCTION PROTOTYPES
// FORWARD DECLARATIONS
// ============================ MEMBER FUNCTIONS ===============================
// Create instance of concrete ECOM interface implementation
CHtiAppServicePlugin* CHtiAppServicePlugin::NewL()
{
CHtiAppServicePlugin* self = new ( ELeave ) CHtiAppServicePlugin;
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop();
return self;
}
// Constructor
CHtiAppServicePlugin::CHtiAppServicePlugin()
{
}
CHtiAppServicePlugin::~CHtiAppServicePlugin()
{
HTI_LOG_FUNC_IN( "~CHtiAppServicePlugin" );
for ( TInt i = 0; i < iProcessHandleArray.Count(); i++ )
{
iProcessHandleArray[i].Close();
}
iProcessHandleArray.Close();
delete iAppServiceUiPlugin;
iLibrary.Close();
HTI_LOG_FUNC_OUT( "~CHtiAppServicePlugin" );
}
//Second phase construction.
void CHtiAppServicePlugin::ConstructL()
{
HTI_LOG_FUNC_IN( "CHtiAppServicePlugin::ConstructL" );
TInt err = iLibrary.Load( KHtiAppControlDll );
HTI_LOG_FORMAT( "HtiAppControlDll library load returned %d", err );
if ( err == KErrNone &&
iLibrary.Type()[1] == KHTIServiceInterfaceUid )
{
HTI_LOG_TEXT( "HtiAppControlDll DLL found" );
TLibraryFunction entry = iLibrary.Lookup( 1 );
if ( entry != NULL )
{
iAppServiceUiPlugin = ( CHTIServicePluginInterface* ) entry();
}
}
else if ( err == KErrNotFound )
{
//No HtiAppControl.dll found so CHtiAppServicePlugin can handle only
//process control commands
HTI_LOG_TEXT( "HtiAppControlDll DLL not found" );
}
HTI_LOG_FUNC_OUT( "CHtiAppServicePlugin::ConstructL" );
}
void CHtiAppServicePlugin::InitL()
{
if ( iAppServiceUiPlugin )
{
iAppServiceUiPlugin->SetDispatcher( iDispatcher );
}
}
TInt CHtiAppServicePlugin::ParseString( const TDesC8& aRequest,
TInt anOffset,
TBool aUnicode,
TDes& aResult )
{
HTI_LOG_FUNC_IN( "CHtiAppServicePlugin::ParseString" );
//validate parameters
//if offset outside the string return empty string
if ( anOffset >= aRequest.Size() )
{
return anOffset;
}
TInt len = aRequest[anOffset];
HTI_LOG_FORMAT( "length %d", len );
if ( len > aResult.MaxLength() )
{
return KErrBadDescriptor;
}
TInt nextOffset = ( aUnicode ? len * 2 : len ) + anOffset + 1;
HTI_LOG_FORMAT( "nextOffset %d", nextOffset );
HTI_LOG_FORMAT( "reqSize %d", aRequest.Size() );
if ( nextOffset > aRequest.Size() )
{
return KErrArgument;
}
if ( aUnicode )
{
const TPtrC8 aFrom( aRequest.Mid( anOffset + 1, len * 2 ) );
aResult.SetLength( len );
for ( TInt i = 0; i < len; ++i )
{
aResult[i] = ( TUint16 ) aFrom[i << 1] +
( ( ( TUint16 ) aFrom[( i << 1 ) + 1] ) << 8 );
}
}
else
{
aResult.Copy( aRequest.Mid( anOffset + 1, len ) );
}
HTI_LOG_FUNC_OUT( "CHtiAppServicePlugin::ParseString" );
return nextOffset;
}
void CHtiAppServicePlugin::ProcessMessageL( const TDesC8& aMessage,
THtiMessagePriority aPriority )
{
HTI_LOG_FUNC_IN( "CHtiAppServicePlugin::ProcessMessage" );
if ( aMessage.Length() < 1 )
{
// no command
SendErrorMsg( KErrArgument, KErrDescrInvalidCmd );
return;
}
if ( aMessage.Length() < 2 &&
aMessage[0] != EListProcesses &&
aMessage[0] != EListProcesses_u )
{
// parameter is required with all command except listing processes
SendErrorMsg( KErrArgument, KErrDescrInvalidCmd );
return;
}
HTI_LOG_FORMAT( "cmd %d", aMessage[0] );
if ( aMessage[0] < EProcessLastCommand )
{
HandleProcessControlL( aMessage );
}
else if ( aMessage[0] <= EUnInstallName )
{
if ( iAppServiceUiPlugin )
{
iAppServiceUiPlugin->ProcessMessageL( aMessage, aPriority );
}
else
{
SendErrorMsg( KErrNotSupported, KErrDescrNotSupported );
}
}
else
{
SendErrorMsg( KErrArgument, KErrDescrInvalidCmd );
}
HTI_LOG_FUNC_OUT( "CHtiAppServicePlugin::ProcessMessage" );
}
void CHtiAppServicePlugin::HandleProcessControlL( const TDesC8& aMessage )
{
HTI_LOG_FUNC_IN( "CHtiAppServicePlugin::HandleProcessControl" );
TBool unicode = aMessage[0] & KUnicodeMask;
HTI_LOG_FORMAT( "unicode %d", unicode );
TFileName programName;
switch ( aMessage[0] )
{
case EStartProcess:
case EStartProcess_u:
{
TFileName cmdLine;
TInt offset = ParseString( aMessage, 1, unicode, programName );
if ( offset >= 0 )
{
offset = ParseString( aMessage, offset, unicode, cmdLine );
if ( offset >= 0 )
{
HandleStartProcessL( programName, cmdLine, EFalse );
}
}
if ( offset < 0 )
{
SendErrorMsg( offset, KErrDescrInvalidArguments );
}
}
break;
case EStopProcess:
case EStopProcess_u:
{
TInt err = ParseString( aMessage, 1, unicode, programName );
if ( err >= 0 )
{
RProcess process;
err = OpenProcessL( process, programName );
if ( err == KErrNone )
{
CleanupClosePushL( process );
HandleStopProcessL( process );
CleanupStack::PopAndDestroy();
}
else if ( err == KErrNotFound )
{
SendMessageL( ENotFound );
}
else
{
SendErrorMsg( err , KErrDescrFailedOpenProcess );
}
}
else
{
SendErrorMsg( err , KErrDescrInvalidArguments );
}
}
break;
case EStopProcess_id:
{
TPtrC8 processId8 = aMessage.Mid( 1 );
if ( processId8.Length() == 4 )
{
RProcess process;
TUint32 processId = Parse32<TUint32>( processId8 );
TInt err = process.Open( TProcessId( processId ) );
if ( err == KErrNone )
{
CleanupClosePushL( process );
HandleStopProcessL( process );
CleanupStack::PopAndDestroy();
}
else if ( err == KErrNotFound )
{
SendMessageL( ENotFound );
}
else
{
SendErrorMsg( err , KErrDescrFailedOpenProcess );
}
}
else
{
SendErrorMsg( KErrArgument , KErrDescrInvalidProcessId );
}
}
break;
case EStatusProcess:
case EStatusProcess_u:
{
TInt err = ParseString( aMessage, 1, unicode, programName );
if ( err >= 0 )
{
RProcess process;
err = OpenProcessL( process, programName );
if ( err == KErrNone )
{
CleanupClosePushL( process );
HandleStatusProcessL( process );
CleanupStack::PopAndDestroy();
}
else if ( err == KErrNotFound )
{
SendMessageL( ENotFound );
}
else
{
SendErrorMsg( err , KErrDescrFailedOpenProcess );
}
}
else
{
SendErrorMsg( err , KErrDescrInvalidArguments );
}
}
break;
case EStatusProcess_id:
{
TPtrC8 processId8 = aMessage.Mid( 1 );
if ( processId8.Length() == 4 )
{
RProcess process;
TUint32 processId = Parse32<TUint32>( processId8 );
TInt err = process.Open( TProcessId( processId ) );
if ( err == KErrNone )
{
CleanupClosePushL( process );
HandleStatusProcessL( process );
CleanupStack::PopAndDestroy();
}
else if ( err == KErrNotFound )
{
SendMessageL( ENotFound );
}
else
{
SendErrorMsg( err , KErrDescrFailedOpenProcess );
}
}
else
{
SendErrorMsg( KErrArgument , KErrDescrInvalidProcessId );
}
}
break;
case EListProcesses:
case EListProcesses_u:
{
if ( aMessage.Length() > 1 )
{
// there is a match pattern as a parameter
TInt err = ParseString( aMessage, 1, unicode, programName );
if ( err >= 0 )
{
HandleListProcessesL( programName );
}
else
{
SendErrorMsg( err , KErrDescrInvalidArguments );
}
}
else
{
// no match pattern defined
HandleListProcessesL( KNullDesC );
}
}
break;
case EStartProcessRetVal:
case EStartProcessRetVal_u:
{
TFileName cmdLine;
TInt offset = ParseString( aMessage, 1, unicode, programName );
if ( offset >= 0 )
{
offset = ParseString( aMessage, offset, unicode, cmdLine );
if ( offset >= 0 )
{
HandleStartProcessL( programName, cmdLine, ETrue );
}
}
if ( offset < 0 )
{
SendErrorMsg( offset, KErrDescrInvalidArguments );
}
}
break;
case EGetProcessExitCode:
{
HTI_LOG_TEXT( "EGetProcessExitCode" );
TPtrC8 processId8 = aMessage.Mid( 1 );
if ( processId8.Length() == 4 )
{
TBool processFound = EFalse;
TUint processId = Parse32<TUint>( processId8 );
RProcess process;
TBuf8<1 + 4 + 1 + KMaxExitCategoryName> response;
HTI_LOG_FORMAT( "Starting to search process with id: %d", processId );
for ( TInt i = 0; i < iProcessHandleArray.Count(); i++ )
{
process = iProcessHandleArray[i];
TUint id = process.Id();
if ( id == processId )
{
HTI_LOG_TEXT( "Matching process found" );
TInt exitReason = process.ExitReason();
response.Append( process.ExitType() );
response.Append( (TUint8*)(&exitReason), 4 );
response.Append( process.ExitCategory().Length() );
response.Append( process.ExitCategory() );
SendMessageL( EOk, response );
// Close the process handle and remove it from the array
// if the process is not running anymore and the exit
// code has been queried.
if ( process.ExitType() != EExitPending )
{
HTI_LOG_TEXT( "Closing and removing the handle" );
iProcessHandleArray[i].Close();
iProcessHandleArray.Remove( i );
}
processFound = ETrue;
break;
}
}
if ( !processFound )
{
SendErrorMsg( KErrNotFound , KErrDescrInvalidProcessId );
}
}
else
{
SendErrorMsg( KErrArgument , KErrDescrInvalidProcessId );
}
}
break;
default:
{
SendErrorMsg( KErrArgument, KErrDescrInvalidCmd );
}
}
HTI_LOG_FUNC_OUT( "CHtiAppServicePlugin::HandleProcessControl" );
}
void CHtiAppServicePlugin::HandleStartProcessL( const TDesC& aProgramName,
const TDesC& aCmdLine,
TBool aStoreProcessHandle )
{
HTI_LOG_FUNC_IN( "CHtiAppServicePlugin::HandleStartProcessL" );
HTI_LOG_FORMAT( "progr name %d", aProgramName.Length() );
HTI_LOG_DES( aProgramName );
RProcess process;
TInt err = process.Create( aProgramName, aCmdLine ); // command parameters
if ( err == KErrNone )
{
CleanupClosePushL( process );
//convert process id to binary des
TUint processId = process.Id();
HTI_LOG_FORMAT( "process id %d", processId );
TBuf8<KTUintLength> processIdDes;
processIdDes.Append(
( TUint8* )( &processId ), KTUintLength );
SendMessageL( EOk, processIdDes );
process.Resume();
if ( aStoreProcessHandle )
{
HTI_LOG_TEXT( "Storing the process handle" );
iProcessHandleArray.Append( process );
CleanupStack::Pop();
}
else
{
CleanupStack::PopAndDestroy();
}
}
else if ( err == KErrNotFound )
{
SendMessageL( ENotFound );
}
else
{
SendErrorMsg( err ,KErrDescrFailedCreateProcess );
}
HTI_LOG_FUNC_OUT( "CHtiAppServicePlugin::HandleStartProcessL" );
}
void CHtiAppServicePlugin::HandleStopProcessL( RProcess& aProcess )
{
if ( aProcess.ExitType() == EExitPending )
{
aProcess.Kill( KTerminateReason );
SendMessageL( EOk );
}
else
{
SendMessageL( EAlreadyStopped );
}
}
void CHtiAppServicePlugin::HandleStatusProcessL( RProcess& aProcess )
{
TExitType exT = aProcess.ExitType();
switch ( exT )
{
case EExitPending:
{
SendMessageL( ERunning );
}
break;
case EExitKill:
case EExitTerminate:
{
SendMessageL( EKilled );
}
break;
case EExitPanic:
{
SendMessageL( EPanic );
}
break;
};
}
void CHtiAppServicePlugin::HandleListProcessesL( const TDesC& aMatch )
{
HTI_LOG_FUNC_IN( "CHtiAppServicePlugin::HandleListProcessesL" );
RProcess process;
TFullName processName;
TUint processId;
TBuf8<KTUintLength> processIdDes;
TExitType exitType;
TBuf8<128> buf;
CBufFlat* processListBuf = NULL;
TRAPD( err, processListBuf = CBufFlat::NewL( 128 ) );
if ( err )
{
SendErrorMsg( err ,KErrDescrNoMemory );
return;
}
CleanupStack::PushL( processListBuf );
// The default match pattern is the single character *
TFindProcess finder;
// if some real match pattern is defined, use it
if ( aMatch.Length() > 0 )
{
HTI_LOG_TEXT( "Match pattern was given:" );
HTI_LOG_DES( aMatch );
finder.Find( aMatch );
}
TInt pos = 0;
TUint numberOfEntries = 0;
while ( finder.Next( processName ) == KErrNone )
{
err = process.Open( finder );
//convert process id to binary des
processId = process.Id();
processIdDes.Append( ( TUint8* ) ( &processId ), KTUintLength );
buf.Append( processIdDes );
// status
exitType = process.ExitType();
switch ( exitType )
{
case EExitPending:
{
buf.Append( ERunning );
}
break;
case EExitKill:
case EExitTerminate:
{
buf.Append( EKilled );
}
break;
case EExitPanic:
{
buf.Append( EPanic );
}
break;
};
// name length
buf.Append( processName.Length() );
// name
buf.Append( processName );
process.Close();
TRAP( err, processListBuf->ExpandL( pos, buf.Length() ) );
if ( err )
{
SendErrorMsg( err , KErrDescrNoMemory );
delete processListBuf;
return;
}
processListBuf->Write( pos, buf, buf.Length() );
pos += buf.Length();
buf.Zero();
processIdDes.Zero();
numberOfEntries++;
}
// insert the number of entries in the beginning
TBuf8<2> entries;
entries.Append( ( TUint8* ) ( &numberOfEntries ), 2 );
processListBuf->ExpandL( 0, 2 );
processListBuf->Write( 0, entries, 2 );
SendMessageL( EOk, processListBuf->Ptr( 0 ) );
CleanupStack::PopAndDestroy( processListBuf );
HTI_LOG_FUNC_OUT( "CHtiAppServicePlugin::HandleListProcessesL" );
}
TInt CHtiAppServicePlugin::OpenProcessL( RProcess& aProcess,
const TDesC& aMatch )
{
HTI_LOG_FUNC_IN( "CHtiAppServicePlugin::OpenProcessL" );
TFullName processName;
TInt err = KErrNone;
TFindProcess finder( aMatch );
err = finder.Next( processName );
if ( err == KErrNone )
{
err = aProcess.Open( finder );
}
HTI_LOG_FUNC_OUT( "CHtiAppServicePlugin::OpenProcessL" );
return err;
}
template<class T> T CHtiAppServicePlugin::Parse32(
const TDesC8& a32int )
{
//manually construct TUint or TInt32
return T( a32int[0] + ( a32int[1] << 8 ) +
( a32int[2] << 16) + ( a32int[3] << 24) );
}
void CHtiAppServicePlugin::SendMessageL( TAppCommand aResponseCode,
const TDesC8& aMsg )
{
HTI_LOG_FORMAT( "SendMessage %d", aResponseCode );
HTI_LOG_FORMAT( "Message len %d", aMsg.Length() );
HBufC8* sendMsg = HBufC8::NewL( 1 + aMsg.Length() );
CleanupStack::PushL( sendMsg );
sendMsg->Des().Append( aResponseCode );
sendMsg->Des().Append( aMsg );
User::LeaveIfError( iDispatcher->DispatchOutgoingMessage(
sendMsg,
KAppServiceUid ) );
CleanupStack::Pop();
}
inline TInt CHtiAppServicePlugin::SendErrorMsg( TInt anError,
const TDesC8& aMsg )
{
return iDispatcher->DispatchOutgoingErrorMessage( anError,
aMsg,
KAppServiceUid );
}
// End of File