sl@0: /* sl@0: * Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * Implements CUpsServer. See class and function definitions for sl@0: * more information. sl@0: * sl@0: */ sl@0: sl@0: sl@0: /** sl@0: @file sl@0: */ sl@0: sl@0: #include "upsserver.h" sl@0: #include "policycache.h" sl@0: #include "pluginmanager.h" sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "authoriser.h" sl@0: #include sl@0: #include "upsserver_p.h" sl@0: sl@0: namespace UserPromptService sl@0: { sl@0: sl@0: static const TInt upsPolicyRangeCount = 8; sl@0: static const TInt upsPolicyRanges[upsPolicyRangeCount] = sl@0: { sl@0: 0, sl@0: // Range 0 - 0 to EBaseSession-1 sl@0: // Not used sl@0: CScsServer::EBaseSession, sl@0: // Range 1 - EBaseSession to EBaseSession | EMngmntRead-1 sl@0: // sl@0: // These codes used to create subsessions and to query the policy sl@0: // authorisation settings. sl@0: // sl@0: // (ESessSubsessFromThreadId/EGetClientConfigLength/EGetClientConfigData) sl@0: // sl@0: CScsServer::EBaseSession | EMngmntRead, sl@0: // Range 2 - EBaseSession | EMngmntRead to EBaseSession | EMngmntDelete - 1 sl@0: // sl@0: // Management READ APIs sl@0: // sl@0: CScsServer::EBaseSession | EMngmntDelete, sl@0: // Range 3 - EBaseSession | EMngmntDelete to EBaseSession | EMngmntUpdate - 1 sl@0: // Management DELETE API (ie. delete entire database or selected entries). sl@0: // sl@0: CScsServer::EBaseSession | EMngmntUpdate, sl@0: // Range 4 - EBaseSession | EMngmntUpdate to EBaseSession | ESwiObserver - 1 sl@0: // Management UPDATE API (ie. change an existing decision). sl@0: // sl@0: CScsServer::EBaseSession | ESwiObserver, sl@0: // Range 5 - EBaseSession | ESwiObserver to EBaseSubSession - 1 sl@0: // SWI observer management API. sl@0: // sl@0: CScsServer::EBaseSubSession, sl@0: // Range 6 - EBaseSubSession to EBaseMustAllow-1 sl@0: // sl@0: // System Server APIs sl@0: // Authorise - (ESubsessPreparePrompt/ESubsessExecutePrompt) sl@0: CScsServer::EBaseMustAllow sl@0: // Range 7 - EBaseMustAllow to KMaxTInt inclusive sl@0: // sl@0: // SCS internal APIs to create subsessions, cancel requests etc. sl@0: }; sl@0: sl@0: static const TUint8 upsPolicyElementsIndex[upsPolicyRangeCount] = sl@0: { sl@0: CPolicyServer::ENotSupported, // Range 0 - Not used sl@0: CPolicyServer::EAlwaysPass, // Range 1 - Subsess and auth policy sl@0: 0, // Range 2 - Management READ APIs sl@0: 1, // Range 3 - Management DELETE APIs sl@0: 2, // Range 4 - Management UPDATE APIs sl@0: 3, // Range 5 - SWI observer APIs sl@0: 4, // Range 6 - System Server APIs sl@0: CPolicyServer::EAlwaysPass // Range 7 - SCS internal sl@0: }; sl@0: sl@0: // 0x102836C3 == Swi::KUidSwiObserver.iUid from swiobserver.h BUT we can not include that because SWI is optional sl@0: // and we are not! sl@0: static const TSecureId KSwiObserverSid(0x102836C3); sl@0: static const CPolicyServer::TPolicyElement upsPolicyPolicyElements[5] = sl@0: { sl@0: {_INIT_SECURITY_POLICY_C1(ECapabilityReadDeviceData), CPolicyServer::EFailClient}, sl@0: {_INIT_SECURITY_POLICY_C1(ECapabilityWriteDeviceData), CPolicyServer::EFailClient}, sl@0: {_INIT_SECURITY_POLICY_C1(ECapabilityAllFiles), CPolicyServer::EFailClient}, sl@0: {_INIT_SECURITY_POLICY_S0(KSwiObserverSid), CPolicyServer::EFailClient}, sl@0: {_INIT_SECURITY_POLICY_C1(ECapabilityProtServ), CPolicyServer::EFailClient} sl@0: }; sl@0: sl@0: static const CPolicyServer::TPolicy upsPolicy = sl@0: { sl@0: CPolicyServer::EAlwaysPass, // Allow all connects sl@0: upsPolicyRangeCount, sl@0: upsPolicyRanges, sl@0: upsPolicyElementsIndex, sl@0: upsPolicyPolicyElements, sl@0: }; sl@0: sl@0: _LIT_SECURITY_POLICY_S0(KAllowUpsServer, KUpsServerUid.iUid); //< Only the UPS server can update the P&S flag used to tell clients to re-read client authorisation policies sl@0: _LIT_SECURITY_POLICY_C1(KAllowProtServ, ECapabilityProtServ); //< All our system server clients will have ProtServ, so limit reading of the (internal) flag to them. sl@0: sl@0: CUpsServer* CUpsServer::NewLC() sl@0: /** sl@0: Factory function allocates new, initialized instance of sl@0: CUpsServer which is left on the cleanup stack. sl@0: sl@0: @return New, initialized instance of CUpsServer sl@0: which is left on the cleanup stack. sl@0: */ sl@0: { sl@0: CUpsServer* self = new(ELeave) CUpsServer(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: return self; sl@0: } sl@0: sl@0: CUpsServer::CUpsServer() sl@0: /** sl@0: Initializes the superclass with this server's version. sl@0: */ sl@0: : CScsServer(UserPromptService::Version(), upsPolicy), sl@0: iPolicyCache(iFs), sl@0: iDbHandle(iFs) sl@0: { sl@0: // empty. sl@0: } sl@0: sl@0: void CUpsServer::ConstructL() sl@0: /** sl@0: Second-phase construction initializes the superclass and sl@0: starts the server. sl@0: */ sl@0: { sl@0: CScsServer::ConstructL(UserPromptService::KShutdownPeriodUs); sl@0: User::LeaveIfError(iFs.Connect()); sl@0: sl@0: TInt r = RProperty::Define(KUpsServiceConfigProperty, RProperty::EInt, KAllowProtServ, KAllowUpsServer); sl@0: if(r != KErrAlreadyExists) sl@0: { sl@0: User::LeaveIfError(r); sl@0: } sl@0: sl@0: iSwiWatcher = CSwiWatcher::NewL(*this); sl@0: sl@0: SetupL(); sl@0: sl@0: StartL(UserPromptService::KUpsServerName); sl@0: } sl@0: sl@0: void CUpsServer::SetupL() sl@0: /** sl@0: Setup memory variables which are not already setup. sl@0: Used during intial construction and after a call to FreeUncompressableMemory. sl@0: */ sl@0: { sl@0: if(!iPolicyCache.IsOpen()) sl@0: { sl@0: iPolicyCache.OpenL(); sl@0: } sl@0: if(!iPluginManager) sl@0: { sl@0: iPluginManager = CPluginManager::NewL(); sl@0: } sl@0: sl@0: // Create/Open the database sl@0: if(!iDbHandle.IsOpen()) sl@0: { sl@0: iDbHandle.OpenL(); sl@0: } sl@0: sl@0: if(!iFlurryQueue) sl@0: { sl@0: iFlurryQueue = CAuthoriserFifo::NewL(); sl@0: } sl@0: if(!iFlurryQueueBeingProcessed) sl@0: { sl@0: iFlurryQueueBeingProcessed = CAuthoriserFifo::NewL(); sl@0: } sl@0: } sl@0: sl@0: void CUpsServer::FreeUncompressableMemory() sl@0: /** sl@0: Frees memory which can not be compressed down to a known level for OOM testing. sl@0: */ sl@0: { sl@0: iDbHandle.Close(); sl@0: sl@0: if(iPluginManager) sl@0: { sl@0: iPluginManager->Unload(); sl@0: delete iPluginManager; sl@0: iPluginManager = 0; sl@0: } sl@0: sl@0: iPolicyCache.Release(); sl@0: } sl@0: sl@0: sl@0: CUpsServer::~CUpsServer() sl@0: /** sl@0: Cleanup the server, in particular close the RFs session. sl@0: */ sl@0: { sl@0: iDisputed.Close(); sl@0: sl@0: (void) RProperty::Delete(KUpsServiceConfigProperty); sl@0: sl@0: delete iFlurryQueueBeingProcessed; sl@0: iFlurryQueueBeingProcessed = 0; sl@0: sl@0: delete iFlurryQueue; sl@0: iFlurryQueue = 0; sl@0: sl@0: FreeUncompressableMemory(); sl@0: sl@0: delete iSwiWatcher; sl@0: iSwiWatcher = 0; sl@0: iFs.Close(); sl@0: } sl@0: sl@0: CScsSession* CUpsServer::DoNewSessionL(const RMessage2& /*aMessage*/) sl@0: /** sl@0: Implement CScsServer by allocating a new instance of CUpsSession. sl@0: sl@0: @param aMessage Standard server-side handle to message. Not used. sl@0: @return New instance of CUpsSession which is owned by the sl@0: caller. sl@0: */ sl@0: { sl@0: return CUpsSession::NewL(*this); sl@0: } sl@0: sl@0: sl@0: void CUpsServer::DoPreHeapMarkOrCheckL() sl@0: /** sl@0: This function is called by the framework just before settingchecking a heap mark. We need to compress/free memory sl@0: down to a state which should be the same both before and after the test operations. sl@0: */ sl@0: { sl@0: #ifdef _DEBUG sl@0: if(iAsyncRequests.Count() != 0) sl@0: { sl@0: User::Leave(KErrServerBusy); sl@0: } sl@0: iDisputed.Compress(); sl@0: iFlurryQueue->Compress(); sl@0: iFlurryQueueBeingProcessed->Compress(); sl@0: FreeUncompressableMemory(); sl@0: #endif sl@0: } sl@0: sl@0: void CUpsServer::DoPostHeapMarkOrCheckL() sl@0: /** sl@0: Called immediately after setting/checking the heap mark and therefore just after DoPreHeapMarkOrCheckL. sl@0: This function needs to re-allocate uncompressable data structures which were destroyed by DoPreHeapMarkOrCheckL. sl@0: */ sl@0: { sl@0: #ifdef _DEBUG sl@0: SetupL(); sl@0: #endif sl@0: } sl@0: sl@0: void CUpsServer::GateKeeperL(CAuthoriser *aAuthoriser) sl@0: /** sl@0: If no dialog is in progress, the server will note one is in sl@0: progress, and tell the aAuthoriser it can continue (by calling sl@0: ClearedToDisplayL). sl@0: sl@0: Whenever a CAuthoriser finishes it MUST call our AuthoriserDone sl@0: function. This will allow us to cleanup our queues and clear sl@0: the next dialog to display. sl@0: sl@0: If a dialog is already in progress, the the aAuthoriser will be sl@0: added to iFlurryQueue for later processing. sl@0: sl@0: @param aAuthoriser to queue sl@0: */ sl@0: { sl@0: if(iCurrentDialog) sl@0: { sl@0: // Add to queue of requests requiring re-processing later. This includes requests which want to display sl@0: // a dialog and ones which matches a recordId which is under dispute (i.e. Where ForcePrompt has been sl@0: // called and returned yes, but the prompt hasn't been displayed yet). sl@0: iFlurryQueue->PushL(aAuthoriser); sl@0: return; sl@0: } sl@0: iCurrentDialog = aAuthoriser; sl@0: iCurrentDialog->ClearedToDisplayL(); sl@0: } sl@0: sl@0: void CUpsServer::AuthoriserDone(CAuthoriser *aAuthoriser) sl@0: /** sl@0: See CUpsServer::AuthoriserDoneL for documentation. sl@0: */ sl@0: { sl@0: TRAP_IGNORE(AuthoriserDoneL(aAuthoriser)); sl@0: } sl@0: sl@0: void CUpsServer::AuthoriserDoneL(CAuthoriser *aAuthoriser) sl@0: /** sl@0: The CAuthoriser has either completed the request, been sl@0: cancelled, or failed somehow. sl@0: sl@0: If it is in either FIFO it needs removing. sl@0: sl@0: If it is the current display dialog, then we need to check the sl@0: FIFOs, and maybe swap them, and call WakeupNextPending. sl@0: */ sl@0: { sl@0: // Remove from lists. sl@0: // Note the FIFO object does NOT leave if the object is not found. sl@0: iFlurryQueue->RemoveL(aAuthoriser); sl@0: iFlurryQueueBeingProcessed->RemoveL(aAuthoriser); sl@0: sl@0: if(aAuthoriser == iCurrentDialog) sl@0: { sl@0: iCurrentDialog = 0; sl@0: sl@0: if(iFlurryQueueBeingProcessed->IsEmpty()) sl@0: { sl@0: // Swap queues sl@0: CAuthoriserFifo *tmp = iFlurryQueue; sl@0: iFlurryQueue = iFlurryQueueBeingProcessed; sl@0: iFlurryQueueBeingProcessed = tmp; sl@0: } sl@0: WakeupNextPendingL(); sl@0: } sl@0: } sl@0: sl@0: void CUpsServer::WakeupNextPendingL() sl@0: /** sl@0: This function does the following:- sl@0: sl@0: 1) If iFlurryQueueBeingProcessed is empty it returns. sl@0: sl@0: 2) Removes the first authoriser from iFlurryQueueBeingProcessed sl@0: and calls SetPending to mark it as no longer pending. sl@0: sl@0: 3) Increases its priority to EPriorityUserInput (this makes sl@0: sure it will be handled ahead of any incoming requests) sl@0: sl@0: 4) Sets it active and completes it so it runs. sl@0: sl@0: It will run BEFORE any incoming requests. sl@0: sl@0: The first thing it must do is call this function again. This sl@0: ensures all pending requests are re-processed in order. sl@0: sl@0: Normally it will then re-lookup its fingerprints in the sl@0: database, if found it may complete client request. If it sl@0: decides it still needs to display a dialog it should call sl@0: GateKeeper again. sl@0: */ sl@0: { sl@0: if(iFlurryQueueBeingProcessed->IsEmpty()) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: CAuthoriser *authoriser = iFlurryQueueBeingProcessed->PopL(); sl@0: // Set priority of authoriser to EPriorityHigh-1. This is higher sl@0: // than any incoming work, but lower than deferred deletes. sl@0: authoriser->SetPriority(CActive::EPriorityHigh - 1); sl@0: authoriser->Wakeup(); sl@0: } sl@0: sl@0: void CUpsServer::DisputeRecordIdL(TUint32 aRecordId) sl@0: /** sl@0: Add the specified record to the list of disputed record IDs. sl@0: */ sl@0: { sl@0: DEBUG_PRINTF2(_L8("CUpsServer::DisputeRecordIdL(%d)\n"), aRecordId); sl@0: User::LeaveIfError(iDisputed.InsertInOrder(aRecordId)); sl@0: } sl@0: sl@0: void CUpsServer::UnDisputeRecordIdL(TUint32 aRecordId) sl@0: /** sl@0: Deletes the specified record from the list of disputed record IDs. sl@0: */ sl@0: { sl@0: DEBUG_PRINTF2(_L8("CUpsServer::UnDisputeRecordIdL(%d)\n"), aRecordId); sl@0: TInt i = iDisputed.FindInOrderL(aRecordId); sl@0: User::LeaveIfError(i); sl@0: iDisputed.Remove(i); sl@0: } sl@0: sl@0: TBool CUpsServer::IsRecordIdDisputed(TUint32 aRecordId) const sl@0: /** sl@0: Checks if the specified record is under dispute. A record is disputed sl@0: if the evaluator ForcePromptL call for a match on that record return ETrue to sl@0: force a prompt to be displayed. sl@0: */ sl@0: { sl@0: TBool disputed = iDisputed.FindInOrder(aRecordId) >= 0; sl@0: //RDebug::Printf("CUpsServer::IsRecordIdDisputed(%d) - returning %s\n", sl@0: // aRecordId, sl@0: // (disputed)?("EFalse"):("EFalse")); sl@0: return disputed; sl@0: } sl@0: sl@0: // sl@0: // Implementation of CSwiWatcher sl@0: // sl@0: CSwiWatcher *CSwiWatcher::NewL(CUpsServer &aUpsServer) sl@0: { sl@0: CSwiWatcher *self = new(ELeave) CSwiWatcher(aUpsServer); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: CSwiWatcher::CSwiWatcher(CUpsServer &aUpsServer) sl@0: : CActive(CActive::EPriorityHigh), sl@0: iUpsServer(aUpsServer) sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: } sl@0: sl@0: void CSwiWatcher::ConstructL() sl@0: /** sl@0: Subscribe for notification for writes to the SWI P&S property. sl@0: We do not check the actual value because it is not guaranteed that we will run for every change. sl@0: */ sl@0: { sl@0: User::LeaveIfError(iSwiProperty.Attach(KUidSystemCategory, KSAUidSoftwareInstallKeyValue)); sl@0: iSwiProperty.Subscribe(iStatus); sl@0: SetActive(); sl@0: } sl@0: sl@0: void CSwiWatcher::RunL() sl@0: /** sl@0: SWI has changed state, so unload any unused plugins. sl@0: We do this for EVERY state change which we manage to run for, which is overkill, but the unload call sl@0: is cheap/free if there are no plugins which require unloading. sl@0: */ sl@0: { sl@0: User::LeaveIfError(iStatus.Int()); sl@0: sl@0: iSwiProperty.Subscribe(iStatus); sl@0: SetActive(); sl@0: sl@0: // Tell the plugin manager to unload plugins which are NOT in use. sl@0: iUpsServer.iPluginManager->Unload(); sl@0: } sl@0: sl@0: void CSwiWatcher::DoCancel() sl@0: { sl@0: iSwiProperty.Cancel(); sl@0: } sl@0: sl@0: CSwiWatcher::~CSwiWatcher() sl@0: { sl@0: Cancel(); sl@0: iSwiProperty.Close(); sl@0: } sl@0: sl@0: sl@0: } // End of namespace UserPromptService sl@0: // End of file