diff -r 000000000000 -r 2f259fa3e83a uifw/AvKon/akncompamode/srv/src/akncompaserver.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uifw/AvKon/akncompamode/srv/src/akncompaserver.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,476 @@ +/* +* Copyright (c) 2007 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 +#include +#include // CCoeEnv +#include // TApaTaskList and friends +#include +#include +#include +#include +#include + +#include "akncompasrv.h" +#include "akncompaserver.h" + +// Flags for KAknCompaModeEffects +const TInt KAknCompaModeEffectsSaved = (1 << 31); +const TInt KAknCompaModeEffectsDisabled = 0x7fffffff; + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +CAknCompaSrvWsEventHandler::CAknCompaSrvWsEventHandler(RWsSession& aWsSession) + : CActive(CActive::EPriorityStandard), iWsSession(aWsSession) + { + CActiveScheduler::Add(this); + IssueRequest(); + } + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +CAknCompaSrvWsEventHandler::~CAknCompaSrvWsEventHandler() + { + Cancel(); + } + +// -------------------------------------------------------------------------- +// Issue request to read from wsrv event queue +// -------------------------------------------------------------------------- +void CAknCompaSrvWsEventHandler::IssueRequest() + { + iWsSession.EventReady(&iStatus); + SetActive(); + } + +// -------------------------------------------------------------------------- +// Event ready in window server event queue +// -------------------------------------------------------------------------- +void CAknCompaSrvWsEventHandler::RunL() + { + // Window server event queue read to purge it in case wsrv sends + // something. As we dont have window group created this is probably + // unneccesary as there seem to be no events. + TWsEvent wsEvent; + iWsSession.GetEvent(wsEvent); + IssueRequest(); + } + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +void CAknCompaSrvWsEventHandler::DoCancel() + { + iWsSession.EventReadyCancel(); + } + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +CAknCompaServer::CAknCompaServer() + :CServer2(CActive::EPriorityStandard) + { + } + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +CAknCompaServer::~CAknCompaServer() + { + delete iThemesCenRep; + delete iAvkonCenRep; + + delete iWsEventHandler; + iWsSession.Close(); + } + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +CServer2* CAknCompaServer::NewLC() + { + CAknCompaServer* self = new (ELeave) CAknCompaServer; + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +void CAknCompaServer::ConstructL() + { + User::LeaveIfError(iWsSession.Connect()); + iThemesCenRep = CRepository::NewL(KCRUidThemes); + iAvkonCenRep = CRepository::NewL(KCRUidAvkon); + + // Check if compa-mode has disabled effects in repository + TInt savedEffects = KAknCompaModeEffectsDisabled; + iAvkonCenRep->Get(KAknCompaModeEffects, savedEffects); + iEffectsDisabled = (savedEffects & KAknCompaModeEffectsSaved) != 0; + + iWsEventHandler = new (ELeave) CAknCompaSrvWsEventHandler(iWsSession); + StartL(KAknCompaSrvName); + } + +// -------------------------------------------------------------------------- +// New session added to server +// -------------------------------------------------------------------------- +void CAknCompaServer::AddSession() + { + iSessionCount++; + } + + +// -------------------------------------------------------------------------- +// Session is closing +// -------------------------------------------------------------------------- +void CAknCompaServer::DropSession() + { + if (--iSessionCount == 0) + { + // Stops the active scheduler. As this server runs in its + // own process this stop effectively kills the process + CActiveScheduler::Stop(); + } + } + +// -------------------------------------------------------------------------- +// Get window server session +// -------------------------------------------------------------------------- +RWsSession& CAknCompaServer::WsSession() + { + return iWsSession; + } + +// -------------------------------------------------------------------------- +// Create a new session +// -------------------------------------------------------------------------- +CSession2* CAknCompaServer::NewSessionL(const TVersion& aVersion, + const RMessage2& /*aMessage*/) const + { + // Check that the version is OK + TVersion v(KAknCompaSrvMajorVersionNumber, + KAknCompaSrvMinorVersionNumber, KAknCompaSrvBuildVersionNumber); + if (!User::QueryVersionSupported(v,aVersion)) + { + User::Leave(KErrNotSupported); + } + + return new (ELeave) CAknCompaSrvSession; + } + +// -------------------------------------------------------------------------- +// Panic server +// -------------------------------------------------------------------------- +void CAknCompaServer::PanicServer(TAknCompaServerPanic aPanic) + { + User::Panic(KAknCompaSrvName, aPanic); + } + +// -------------------------------------------------------------------------- +// Panic client +// -------------------------------------------------------------------------- +void CAknCompaServer::PanicClient(const RMessage2& aMessage, + TInt aPanic) + { + aMessage.Panic(KAknCompaSrvName, aPanic); + } + +// -------------------------------------------------------------------------- +// Check if process is a server that displays global +// notes/notifications (Eikon server, Avkon notify and cap servers) +// -------------------------------------------------------------------------- +TBool CAknCompaServer::IsGlobalUiSrv(const RMessage2& aMessage) + { + const TUint32 KEikSrvUid = 0x10003a4a; + return aMessage.SecureId().iId == KAknCapServerUid.iUid || + aMessage.SecureId().iId == KCommonNotifierAppSrvUid.iUid || + aMessage.SecureId().iId == KEikSrvUid; + } + +// -------------------------------------------------------------------------- +// Set thread priority to normal +// -------------------------------------------------------------------------- +void CAknCompaServer::SetThreadPriorityNormal(TAny* /*aUnused*/) + { + RThread thread; + thread.SetPriority(EPriorityNormal); + } + +// -------------------------------------------------------------------------- +// Set thread priority higher than any non-signed application threads +// -------------------------------------------------------------------------- +void CAknCompaServer::SetThreadPriorityHigh() + { + RThread thread; + thread.SetPriority(EPriorityAbsoluteRealTime1); + } + +// -------------------------------------------------------------------------- +// Disable transition effects +// -------------------------------------------------------------------------- +void CAknCompaServer::DisaTransEffectsL(const RMessage2& aMessage) + { + if (!iEffectsDisabled) + { + // Allow effects control only from global ui servers + if (!IsGlobalUiSrv(aMessage)) + { + User::Leave(KErrPermissionDenied); + } + iEffectsDisabled = ETrue; + // The only way to disable transition effects is through CenRep. The + // same variable is also controlled by "Control Panel". If the device + // is turned off while we have disabled effects, we need to enable + // them when device is restarted. + TInt savedEffects = KAknCompaModeEffectsDisabled; + iAvkonCenRep->Get(KAknCompaModeEffects, savedEffects); + + if ((savedEffects & KAknCompaModeEffectsSaved) == 0) + { + TInt effects = 0; + iThemesCenRep->Get(KThemesTransitionEffects, effects); + if (effects != KAknCompaModeEffectsDisabled) + { + iAvkonCenRep->Set(KAknCompaModeEffects, + effects | KAknCompaModeEffectsSaved); + iThemesCenRep->Set(KThemesTransitionEffects, + KAknCompaModeEffectsDisabled); + } + } + } + } + +// -------------------------------------------------------------------------- +// Restore transition effects to a state before they were disabled +// -------------------------------------------------------------------------- +void CAknCompaServer::RestoreTransEffectsL(const RMessage2& aMessage) + { + if (iEffectsDisabled) + { + // Allow effects control only from global ui servers + if (!IsGlobalUiSrv(aMessage)) + { + User::Leave(KErrPermissionDenied); + } + iEffectsDisabled = EFalse; + + // Read saved effects state from our CenRep + TInt savedEffects = 0; + iAvkonCenRep->Get(KAknCompaModeEffects, savedEffects); + + if (savedEffects & KAknCompaModeEffectsSaved) + { + savedEffects &= ~KAknCompaModeEffectsSaved; + iThemesCenRep->Set(KThemesTransitionEffects, savedEffects); + iAvkonCenRep->Set(KAknCompaModeEffects, savedEffects); + } + } + } + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +CAknCompaServer& CAknCompaSrvSession::Server() + { + return *static_cast + (const_cast(CSession2::Server())); + } + +// -------------------------------------------------------------------------- +// Create session +// -------------------------------------------------------------------------- +void CAknCompaSrvSession::CreateL() + { + // Allocate memory for keystate array to hold all possible keys. + // This avoid possibility of memory allocation error when key is + // added to key state array due to key press while application is + // executing. + iKeyState.Reserve(EKeyStateGranularity); + + Server().AddSession(); + } + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +CAknCompaSrvSession::CAknCompaSrvSession(): + iKeyState(EKeyStateGranularity) + { + // We allow only rocker keys, softkeys and numeric keypad keys to be + // simulated. + static const TUint8 ValidScanCodes[] = + { + EStdKeyDevice0, EStdKeyUpArrow, EStdKeyDevice1, EStdKeyLeftArrow, + EStdKeyDevice3, EStdKeyRightArrow, EStdKeyRightShift, + EStdKeyDownArrow, EStdKeyBackspace, EStdKeyNkpAsterisk, EStdKeyHash, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 + }; + iValidScanCodes.Set(ValidScanCodes, sizeof(ValidScanCodes)); + } + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +CAknCompaSrvSession::~CAknCompaSrvSession() + { + TInt num = iKeyState.Count(); + + // When session closes, send key up events for all keys being in down + // state. This ensures even if application crashes that no keys are left + // down. + for( TInt i=0; i < num; i++) + { + SimulateKeyEvent(iKeyState[i], EFalse); + } + Server().DropSession(); + iKeyState.Close(); + } + + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +void CAknCompaSrvSession::ServiceL(const RMessage2& aMessage) + { + TRAPD(err, DispatchMessageL(aMessage)); + aMessage.Complete(err); + } + +// -------------------------------------------------------------------------- +// +// -------------------------------------------------------------------------- +void CAknCompaSrvSession::DispatchMessageL(const RMessage2& aMessage) + { + switch(aMessage.Function()) + { + case ECompaSrvSimulateKeyEvent: + SimulateKeyEventServiceL(aMessage); + break; + case ECompaSrvDisaTransEffects: + Server().DisaTransEffectsL(aMessage); + break; + case ECompaSrvRestoreTransEffects: + Server().RestoreTransEffectsL(aMessage); + break; + // Requests that we don't understand at all are a different matter. + // This is considered a client programming error, so we panic the + // client - this also completes the message. + default: + CAknCompaServer::PanicClient(aMessage, EBadRequest); + } + } + +// -------------------------------------------------------------------------- +// Simulate key event for client application +// -------------------------------------------------------------------------- +void CAknCompaSrvSession::SimulateKeyEventServiceL(const RMessage2& aMessage) + { + TInt scancode = aMessage.Int0(); + TBool keyDown = aMessage.Int1(); + + // Check that scan code is valid. Client request will fail with error + // code KErrNotFound if the check fails. + TChar ch(scancode); + User::LeaveIfError(iValidScanCodes.Locate(ch)); + + if (keyDown) + { + // Set thread priority to very high. The purpose is to prevent + // other threads to change foreground application in between + // client foreground status check and SimulateRawEvent(). + CAknCompaServer::SetThreadPriorityHigh(); + CleanupStack::PushL( + TCleanupItem(CAknCompaServer::SetThreadPriorityNormal, NULL)); + // Check that client task is foreground + CheckKeyDownPermissionL(aMessage); + } + + // Keeps tracks which scancodes are in down state + if (keyDown) + { + // There can be only one of each scancode in the list + if (iKeyState.Find(scancode) == KErrNotFound) + { + iKeyState.AppendL(scancode); + SimulateKeyEvent(scancode, keyDown); + } + CleanupStack::PopAndDestroy(); + } + else + { + TInt pos = iKeyState.Find(scancode); + if (pos != KErrNotFound) + { + iKeyState.Remove(pos); + iKeyState.GranularCompress(); + SimulateKeyEvent(scancode, keyDown); + } + } + } + +// -------------------------------------------------------------------------- +// Simulate key event to window server +// -------------------------------------------------------------------------- +void CAknCompaSrvSession::SimulateKeyEvent(TInt aScancode, TBool aKeyDown) + { + TRawEvent event; + event.Set( + aKeyDown ? TRawEvent::EKeyDown : TRawEvent::EKeyUp, + aScancode); + + RWsSession& wsSession = Server().WsSession(); + // Simulate key event as it came from a keypad + wsSession.SimulateRawEvent(event); + wsSession.Flush(); + } + +// -------------------------------------------------------------------------- +// Check whether client key event request can be executed +// -------------------------------------------------------------------------- +void CAknCompaSrvSession::CheckKeyDownPermissionL(const RMessage2& aMessage) + { + // We try to increase security by allowing only foreground application + // to set key down. As the simulated key events are sent to the + // foreground application by window server, the application is + // sending a key event to itself. + + // Granted if client has ECapabilitySwEvent or request is coming from + // EikSrv. TApaTaskList won't report EikSrv in foreground though + // it's displaying a note. + if (!aMessage.HasCapability(ECapabilitySwEvent) && + !CAknCompaServer::IsGlobalUiSrv(aMessage)) + { + // Allow key down only from a foreground task + TApaTaskList tasklist(Server().WsSession()); + TApaTask foregroundTask = tasklist.FindByPos(0); + + RThread thread; + User::LeaveIfError(thread.Open(foregroundTask.ThreadId())); + TSecurityPolicy securityPolicy(thread.SecureId()); + thread.Close(); + + if (!securityPolicy.CheckPolicy(aMessage)) + { + User::Leave(KErrPermissionDenied); + } + } + }