installationservices/swi/source/sislauncher/server/sislauncherserver.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 15:21:33 +0300
branchRCL_3
changeset 25 7333d7932ef7
parent 0 ba25891c3a9e
child 26 8b7f4e561641
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2004-2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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: 
* SisLauncher - server implementation
*
*/


/**
 @file 
 @released
 @internalComponent
*/
 
#include "sislauncherserver.h"
#include "sislaunchersession.h"
#include "sislauncherclientserver.h"
#include "log.h"
#include "securitypolicy.h"
#include <w32std.h>

#include "threadmonitor.h"
#include "queueprocessor.h"

#ifndef SWI_TEXTSHELL_ROM
    #include <apmstd.h>
    #include <apgcli.h>
    #include <apgwgnam.h>
    #include <apgtask.h>
#endif

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
const TUint KInstallServerUid = 0x101F7295;
const TUint KSisRegistryServerUid = 0x10202DCA;
#endif

using namespace Swi;

CServer2* CSisLauncherServer::NewLC()
    {
    CSisLauncherServer* self=new(ELeave) CSisLauncherServer;
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

CSisLauncherServer::~CSisLauncherServer()
    {
#ifndef SWI_TEXTSHELL_ROM
    if (iBootMode != KTextShell)
        {
        iWsSession.Close(); 
        }
#endif
    delete iShutdown;
    delete iQueueProcessor;
    CSecurityPolicy::ReleaseResource();
    }

void CSisLauncherServer::ConstructL()
    {
    StartL(KSisLauncherServerName);
    iShutdown = new (ELeave) CSisLauncherServerShutdown;
    iShutdown->ConstructL();
    TInt connectErr = KErrNotFound;
#ifndef SWI_TEXTSHELL_ROM
    // Connect to Window Session
    connectErr = iWsSession.Connect();
    if (connectErr != KErrNotFound)
        {
        User::LeaveIfError(connectErr);
        }
#endif
    if (connectErr == KErrNotFound)
        {
        // emulator tests running in textshell or in textshell ROM (#def SWI_TEXTSHELL_ROM)
        iBootMode = KTextShell;
        }
    iQueueProcessor = CQueueProcessor::NewL(*this);
    }

CSession2* CSisLauncherServer::NewSessionL(const TVersion&,const RMessage2&) const
    {
    return new(ELeave) CSisLauncherSession();
    }

void CSisLauncherServer::AddSession()
    {
    ++iSessionCount;
    
    DEBUG_PRINTF2(_L8("Sis Launcher Server - Adding Session (%d sessions total.)"), iSessionCount);
    
    CancelShutdown();   
    }

void CSisLauncherServer::DropSession()
    {
    --iSessionCount;
    
    DEBUG_PRINTF2(_L8("Sis Launcher Server - Dropping Session (%d sessions total.)"), iSessionCount);
    
    if (0==iSessionCount && iShutdown)
        {
        DEBUG_PRINTF(_L8("Sis Launcher Server - Starting shutdown timer."));
        // ignored if a long timer is active
        iShutdown->StartShort(EFalse);
        } 
    }
/**
 * Cancels an existing shutdown timer before renabling with the long timeout. This is used to catch
 * the case where we need to allow ECOM to work before killing the server. ECOM should finish scanning 
 * files within a couple of seconds of SWI finishing but just in case we allow ECOM a little longer.
 * The other reason we have the timer is to handle the case where SWI mistakenly identified a plugin 
 * resource file, we don't want to hang around forever waiting for an event that never comes.
 * */
void CSisLauncherServer::LongServerShutdown()
    {
    DEBUG_PRINTF(_L8("Sis Launcher Server - Switching to long shutdown timer"));
    if (iShutdown)
        {
        iShutdown->StartLong();
        }
    }

void CSisLauncherServer::CancelShutdown()
    {
    DEBUG_PRINTF(_L8("Sis Launcher Server - Cancelling shutdown timer"));
        
    if (iShutdown)
        {
        iShutdown->Cancel();
        }   
    }

void CSisLauncherServer::ShortServerShutdown()
    {
    DEBUG_PRINTF(_L8("Sis Launcher Server - Re-enabling short shutdown timer"));
    if (0==iSessionCount && iShutdown)
        {
        DEBUG_PRINTF(_L8("Sis Launcher Server - Starting shutdown timer"));
        iShutdown->StartShort(ETrue);
        } 
    }

const TInt CSisLauncherServer::iRanges[iRangeCount] = 
    {
    0, // All connect attempts
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
    EParseSwTypeRegFile,                                // accessible by Installserver 
    EUnregisterSifLauncherMimeTypes,                    // accessible by SisRegistryServer
    ENotifyApparcForApps,                               // accessible by Installserver and SisRegistry
    EAsyncParseResourceFileSize,                        // accessible by all clients
#endif
    ESeparatorEndAll,
    };

const TUint8 CSisLauncherServer::iElementsIndex[iRangeCount] = 
    {
    0, // Used by Client which is only swis and TCB is needed.
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
    1, // Utility services used by InstallServer
    2, // Utility services used by SisRegistryServer
    CPolicyServer::ECustomCheck,
    CPolicyServer::EAlwaysPass,
#endif  
    CPolicyServer::ENotSupported,
    };

const CPolicyServer::TPolicyElement CSisLauncherServer::iPolicyElements[] = 
    {
    {_INIT_SECURITY_POLICY_C1(ECapabilityTCB), CPolicyServer::EFailClient},
#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
    {_INIT_SECURITY_POLICY_S0(KInstallServerUid), CPolicyServer::EFailClient},
    {_INIT_SECURITY_POLICY_S0(KSisRegistryServerUid), CPolicyServer::EFailClient},  
#endif
    };

const CPolicyServer::TPolicy CSisLauncherServer::iPolicy =
    {
    0,                  //specifies all connect attempts need TCB
    iRangeCount,
    iRanges,
    iElementsIndex,
    iPolicyElements,
    };
    
    
// shutdown timer

CSisLauncherServerShutdown::~CSisLauncherServerShutdown()
    {
    Cancel();
    }

void CSisLauncherServerShutdown::RunL()
    {
    CActiveScheduler::Stop();
    }
    
void CSisLauncherServerShutdown::StartShort(TBool aCancelLongTimer)
    {
    if (iLongTimerActive & !aCancelLongTimer)
        {
        return;
        }
    else
        {
        Cancel();
        iLongTimerActive=EFalse;
        After(KSisLauncherShutdownDelay);
        }
    }

inline void CSisLauncherServerShutdown::StartLong()
    {
    Cancel();
    iLongTimerActive=ETrue;
    After(KSisLauncherLongShutdownDelay);
    }


void CSisLauncherServer::RunExecutableL(const TDesC& aFileName, TBool aWait)
    {
    DEBUG_CODE_SECTION(
        if (aWait)
            {
            DEBUG_PRINTF2(_L("Sis Launcher Server - Attempting to run executable by filename ('%S'), waiting for termination."),
                &aFileName);
            }
        else
            {
            DEBUG_PRINTF2(_L("Sis Launcher Server - Attempting to run executable by filename ('%S'), not waiting for termination."),
                &aFileName);
            }
    ); // DEBUG_CODE_SECTION
    
    RProcess process;
    _LIT(KNullArgs, "");
    User::LeaveIfError(process.Create(aFileName, KNullArgs));
    CleanupClosePushL(process);
    
    // Get the thread id of the main thread in the process
    // From CApaExeRecognizer::RunL 
    TFullName fullName(process.Name());
    _LIT(KCCMain,"::Main");
    fullName.Append(KCCMain);
    TFindThread fT(fullName);
    User::LeaveIfError(fT.Next(fullName));
    RThread thread;
    User::LeaveIfError(thread.Open(fT));
    TThreadId threadId = thread.Id();
    thread.Close();
    process.Resume();
    
    CleanupStack::PopAndDestroy(&process);
    if (aWait)
        HandleShutdownL(threadId, ETrue);
    }

void CSisLauncherServer::ForceShutdownL(TUid aUid)
    {
    TBool needToScanFullList;
    TFullName fullName;
    do
        {
        needToScanFullList = EFalse;
        TFindProcess findProcess;

        while(findProcess.Next(fullName) == KErrNone)
            {
            RProcess process;
            User::LeaveIfError(process.Open(findProcess));
            TUid sid(process.SecureId());
            if (sid == aUid && process.ExitType() == EExitPending)
                {
                process.Kill(KErrNone);
                needToScanFullList = ETrue;
                }
            process.Close();
            }
        } while (needToScanFullList);
    }


void CSisLauncherServer::HandleShutdownL(TThreadId aThread, TBool aKillOnTimeout)
    {
    RWsSession* wsSession = NULL;
    if (iBootMode == KTextShell) 
        {
        // emulator tests running in textshell or in textshell ROM (#def SWI_TEXTSHELL_ROM)
        DEBUG_PRINTF(_L8("Sis Launcher Server - textshell - skipping shutdown of user applications"));  
        }
    else
        {
        #ifndef SWI_TEXTSHELL_ROM
            DEBUG_CODE_SECTION(
                if (aKillOnTimeout)
                    {
                    DEBUG_PRINTF(_L8("Sis Launcher Server - Awaiting thread shutdown, will forcibly kill process on timeout."));
                    }
                else
                    {
                    DEBUG_PRINTF(_L8("Sis Launcher Server - Awaiting thread shutdown, will not forcibly kill process on timeout."));
                    }
                );
            wsSession = &iWsSession;    
        #endif
        }
    // Read timeout value from software install security
    // policy.
    CSecurityPolicy* secPolicy = CSecurityPolicy::GetSecurityPolicyL();
    TInt runWaitTimeout = secPolicy->RunWaitTimeout();
    TInt shutdownTimeout = secPolicy->ApplicationShutdownTimeout();
    // Wait until the thread finishes or a timeout occurs
    CThreadMonitor* threadMonitor = CThreadMonitor::NewLC(aThread, wsSession);
    threadMonitor->SyncShutdownL(runWaitTimeout, aKillOnTimeout, shutdownTimeout);
    CleanupStack::PopAndDestroy(threadMonitor);
    }

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
CPolicyServer::TCustomResult CSisLauncherServer::CustomSecurityCheckL(const RMessage2& aMsg, 
    TInt& /*aAction*/, TSecurityInfo& /*aMissing*/)
    {
    TUint32 secureId = aMsg.SecureId().iId;
    if (secureId == KInstallServerUid || secureId == KSisRegistryServerUid)
        {
        return CPolicyServer::EPass;
        }
    else
        {
        //client accessing the function is neither Install Server nor Sis Registry
        return CPolicyServer::EFail;
        }
    }
#endif

#ifndef SWI_TEXTSHELL_ROM
void CSisLauncherServer::StartDocumentL(RFile& aFile, TBool aWait)
    {
    DEBUG_CODE_SECTION(
    if (aWait)
        {
        DEBUG_PRINTF(_L8("Sis Launcher Server - Attempting to start document by filehandle, waiting for termination."));
        }
    else
        {
        DEBUG_PRINTF(_L8("Sis Launcher Server - Attempting to start document by filehandle, not waiting for termination."));
        }
    );

    RApaLsSession apaSession;
    User::LeaveIfError(apaSession.Connect());
    CleanupClosePushL(apaSession);

    TThreadId threadId; 
    User::LeaveIfError(apaSession.StartDocument(aFile, threadId));

    CleanupStack::PopAndDestroy(&apaSession);
    if (aWait)
        HandleShutdownL(threadId);
    }

void CSisLauncherServer::StartByMimeL(RFile& aFile, TDesC8& aMimeType, TBool aWait)
    {
    DEBUG_CODE_SECTION(
    if (aWait)
        {
        DEBUG_PRINTF2(_L8("Sis Launcher Server - Attempting to start document by mimetype '%S' (filehandle supplied), waiting for termination."),
            &aMimeType);
        }
    else
        {
        DEBUG_PRINTF2(_L8("Sis Launcher Server - Attempting to start document by mimetype '%S' (filehandle supplied), not waiting for termination."),
            &aMimeType);
        }
    );

    RApaLsSession apaSession;
    User::LeaveIfError(apaSession.Connect());
    CleanupClosePushL(apaSession);

    TThreadId threadId;
    TDataType dataType = TDataType(aMimeType);  
    User::LeaveIfError(apaSession.StartDocument(aFile, dataType, threadId));

    CleanupStack::PopAndDestroy(&apaSession);
    if (aWait)
        HandleShutdownL(threadId);
    }
    
void CSisLauncherServer::StartDocumentL(const TDesC& aFileName, TBool aWait)
    {
    DEBUG_CODE_SECTION(
    if (aWait)
        {
        DEBUG_PRINTF2(_L("Sis Launcher Server - Attempting to start document by filename '%S', waiting for termination."),
            &aFileName);
        }
    else
        {
        DEBUG_PRINTF2(_L("Sis Launcher Server - Attempting to start document by filename '%S', not waiting for termination."),
            &aFileName);
        }
    );

    RApaLsSession apaSession;
    User::LeaveIfError(apaSession.Connect());
    CleanupClosePushL(apaSession);

    TThreadId threadId;
    User::LeaveIfError(apaSession.StartDocument(aFileName, threadId));

    CleanupStack::PopAndDestroy(&apaSession);
    if (aWait)
        HandleShutdownL(threadId);
    }

void CSisLauncherServer::StartByMimeL(const TDesC& aFileName, TDesC8& aMimeType, TBool aWait)
    {
    DEBUG_CODE_SECTION(
    if (aWait)
        {
        DEBUG_PRINTF2(_L("Sis Launcher Server - Attempting to start document by filename '%S', waiting for termination."),
            &aFileName);
        }
    else
        {
        DEBUG_PRINTF2(_L("Sis Launcher Server - Attempting to start document by filename '%S', not waiting for termination."),
            &aFileName);
        }
    );
    DEBUG_PRINTF2(_L8("Sis Launcher Server - Supplied MIME type is '%S'."), &aMimeType);    

    RApaLsSession apaSession;
    User::LeaveIfError(apaSession.Connect());
    CleanupClosePushL(apaSession);

    TThreadId threadId;
    TDataType dataType = TDataType(aMimeType);
    User::LeaveIfError(apaSession.StartDocument(aFileName, dataType, threadId));

    CleanupStack::PopAndDestroy(&apaSession);
    if (aWait)
        HandleShutdownL(threadId);
    }

void CSisLauncherServer::ShutdownL(TUid aUid, TInt aTimeout)
    {
    // This method shuts down running exes matching the SID provided in aUid.
    // It first attempts a graceful shutdown, killing processes if a graceful
    // shutdown is not supported or fails to work within aTimeout microseconds.

    DEBUG_PRINTF2(_L8("Sis Launcher Server - Attempting to kill process with SID: 0x%08x."),
        aUid.iUid);

    TInt wgId=0;

    CApaWindowGroupName* wgName = CApaWindowGroupName::NewL(iWsSession);
    CleanupStack::PushL(wgName);
    CApaWindowGroupName::FindByAppUid(aUid, iWsSession, wgId);
    
    while (wgId != KErrNotFound)
        {   
        wgName->ConstructFromWgIdL(wgId);
        if(wgName->RespondsToShutdownEvent())
            {
            TApaTask task(iWsSession);
            task.SetWgId(wgId);

            RThread thread;
            User::LeaveIfError(thread.Open(task.ThreadId()));
            CleanupClosePushL(thread);
            
            RProcess process;
            User::LeaveIfError(thread.Process(process));
            CleanupClosePushL(process);

            TRequestStatus processStatus;
            process.Logon(processStatus);
            
            task.SendSystemEvent(EApaSystemEventShutdown);

            RTimer timer;
            CleanupClosePushL(timer);
            TRequestStatus timerStatus;
            timer.CreateLocal();
            timer.After(timerStatus, aTimeout);

            User::WaitForRequest(processStatus,timerStatus);

            if (processStatus==KRequestPending)
                {
                // Failed to terminate gracefully, so kill the task.
                DEBUG_PRINTF(_L8("Sis Launcher Server - Process did not die before timeout. Forcibly killing it."));
                process.Kill(KErrNone);
                }
            else if (timerStatus==KRequestPending)
                {
                // Rendezvous completed so cancel timer
                timer.Cancel();
                }
            // Handle second request
            User::WaitForRequest(processStatus,timerStatus);
            CleanupStack::PopAndDestroy(3, &thread);
            }

        // See if there's another instance of this App running.
        CApaWindowGroupName::FindByAppUid(aUid, iWsSession, wgId);
        }
    CleanupStack::PopAndDestroy(wgName);
    }

void CSisLauncherServer::ShutdownL()
    {
    TInt wgId=0;
    
    CApaWindowGroupName* wgName = CApaWindowGroupName::NewL(iWsSession);
    CleanupStack::PushL(wgName);
    TBuf<1> matchAny;
    matchAny.Append(KMatchAny);
    CApaWindowGroupName::FindByCaption(matchAny, iWsSession, wgId);
    while (wgId != KErrNotFound)
        {
        wgName->ConstructFromWgIdL(wgId);
        //DEF057706 - shut down hidden apps during uninstallation if
        // SH flag is specified
        if (!wgName->IsSystem() /* && !wgName->Hidden() */)
            {
            // leave if we cannot shutdown the app because its busy
            if(!wgName->IsBusy())
                {
                TApaTask task(iWsSession);
                task.SetWgId(wgId);
                // show shutdown dialog for this app?
                task.SendSystemEvent(EApaSystemEventShutdown);
                }
            else
                {
                // could not shutdown an app
                User::Leave(KErrInUse);
                }
            }
    
        // get next app to shutdown
        CApaWindowGroupName::FindByCaption(matchAny, iWsSession, wgId);
        }
    CleanupStack::PopAndDestroy(wgName);
    }

void CSisLauncherServer::NotifyNewAppsL(const RPointerArray<TDesC>& aFiles)
    {
    RApaLsSession apaSession;
    User::LeaveIfError(apaSession.Connect());
    CleanupClosePushL(apaSession);

    // UI frameworks advise ignoring the return code
    apaSession.ForceRegistration(aFiles);

    CleanupStack::PopAndDestroy();
    }

#ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK
void CSisLauncherServer::NotifyNewAppsL(const RPointerArray<Usif::CApplicationRegistrationData>& aApplicationRegistrationData)
    {
    RApaLsSession apaSession;
    User::LeaveIfError(apaSession.Connect());
    CleanupClosePushL(apaSession);

    // UI frameworks advise ignoring the return code
    // Proceeding even if force registration fails so that installation is not aborted
    apaSession.ForceRegistration(aApplicationRegistrationData);
    CleanupStack::PopAndDestroy();
    }

#endif
#endif