launcher/src/launcherengine.cpp
branchRCL_3
changeset 22 fad26422216a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/launcher/src/launcherengine.cpp	Wed Sep 01 12:30:35 2010 +0100
@@ -0,0 +1,1800 @@
+/*
+* 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:  
+*
+*/
+
+
+
+#include <aknnotewrappers.h>
+#include <avkon.hrh>
+#include <AknWaitDialog.h>
+#include <AknGlobalNote.h>
+#include <coeutils.h> 
+#include <AknCommonDialogs.h>
+#include <eikprogi.h>
+
+#include <launcher.rsg>
+
+#include "launcherappui.h"
+#include "launcherengine.h"
+#include "launcher.hrh"
+#include "launcherviewapps.h"
+#include "launcherviewoutput.h"
+#include "launchercontainerapps.h"
+#include "launchercontaineroutput.h"
+#include "launcherdllparser.h"
+#include "launcherxmlparser.h"
+
+#include <CMessageData.h>
+#include <e32std.h>
+#include <w32std.h>
+#include <apgtask.h>
+#include <bautils.h>
+#include <s32file.h>
+#include <pathinfo.h> 
+#include <e32cmn.h>
+
+#include "launchertraces.h"
+#include "e32image.h"
+
+_LIT(KLogFileName, "LauncherLog.txt");
+_LIT(KBCLogFileName, "LauncherBCLog.txt");
+_LIT(KSystemDllsFileName, "SystemDlls.txt");
+_LIT(KRequiredDllsFileName, "RequiredDlls.xml");
+_LIT(KDotXML,".xml");
+_LIT(KDotLauncherXML,".launcherxml");
+
+_LIT(KFileSeparator, "\t");
+_LIT(KFileNewLine, "\r\n");
+
+const TInt KMaxAppsArraySize=250;
+const TInt KMaxDllArraySize=5000;
+const TInt KLauncherLogBufferSize = 4096;
+
+// After this many issues, issues are buffered and printed 
+// in the end of analysis
+const TInt KBigBufferUsageThreshold=10;
+
+// Buffer allocation unit
+const TInt KBigBufferAllocBytes=1024;
+
+// ---------------------------------------------------------------------------
+
+CLauncherEngine* CLauncherEngine::NewL(CLauncherAppUi* aAppUi)
+    {
+    CLauncherEngine* self = new(ELeave) CLauncherEngine;
+    CleanupStack::PushL(self);
+    self->ConstructL(aAppUi);
+    CleanupStack::Pop();
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+
+CLauncherEngine::CLauncherEngine() : CActive(EActivePriorityIpcEventsHigh)
+    {
+    }
+
+// ---------------------------------------------------------------------------
+
+template <typename T>
+void AppendLogBufferL(const T& aText, HBufC8*& aBuf)
+    {
+    if( aBuf == 0 )
+        {
+        aBuf = HBufC8::NewL(KLauncherLogBufferSize);
+        }
+    
+    TInt currentMaxLength = aBuf->Des().MaxLength();
+    if( aBuf->Des().Length() + aText.Length() > currentMaxLength )
+        {
+        TInt increaseSize = Max(aText.Length(), KLauncherLogBufferSize);                
+        aBuf = aBuf->ReAllocL(aBuf->Des().MaxLength() + increaseSize );
+        }
+    aBuf->Des().Append(aText);        
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::ConstructL(CLauncherAppUi* aAppUi)
+    {
+    LOGSTRING("Launcher: CLauncherEngine::ConstructL");
+
+    iAppUi = aAppUi;
+    iEnv = CEikonEnv::Static();
+    iLaunchingIsActive = EFalse;
+    iDLLAnalysisIsActive = EFalse;
+    iSkipHiddenAndEmbedOnly = ETrue;
+
+    User::LeaveIfError(iTimer.CreateLocal());
+
+    User::LeaveIfError(iLs.Connect());
+    User::LeaveIfError(iWs.Connect());
+
+    iAppThreadChecker = CAppThreadChecker::NewL(this);
+    iAppRunningChecker = CAppRunningChecker::NewL(this);
+
+    iAllAppsArray = new(ELeave) CDesCArrayFlat(KMaxAppsArraySize);
+    iAppsArray = new(ELeave) CDesCArrayFlat(KMaxAppsArraySize);
+    iSystemDllArray = new(ELeave) CDesCArrayFlat(KMaxDllArraySize);
+
+    iLogWriteBuf = HBufC8::NewL(KLauncherLogBufferSize);
+
+    iLogFilePath = PathInfo::PhoneMemoryRootPath();
+    iLogFilePath.Append( KLogFileName );
+    
+    iBCLogFilePath = PathInfo::PhoneMemoryRootPath();
+    iBCLogFilePath.Append( KBCLogFileName );
+
+    iSystemDllsFilePath = PathInfo::PhoneMemoryRootPath();
+    iSystemDllsFilePath.Append( KSystemDllsFileName );
+
+    iRequiredDllsFilePath = PathInfo::PhoneMemoryRootPath();
+    iRequiredDllsFilePath.Append( KRequiredDllsFileName );
+            
+    iDLLParser = CLauncherDLLParser::NewL();
+
+    CActiveScheduler::Add(this);
+    }
+
+// ---------------------------------------------------------------------------
+
+CLauncherEngine::~CLauncherEngine()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::~CLauncherEngine");
+
+    Cancel();
+
+    // close the log
+    iLogFile.Close();
+    iBCLogFile.Close();
+    if (iLogWriteBuf)
+        delete iLogWriteBuf;
+
+    if (iAppRunningChecker)
+        delete iAppRunningChecker;
+    
+    if (iAppThreadChecker)
+        delete iAppThreadChecker;
+
+    if (iSystemDllArray)
+        {
+        iSystemDllArray->Reset();
+        delete iSystemDllArray;
+        }
+
+    if (iAppsArray)
+        {
+        iAppsArray->Reset();
+        delete iAppsArray;
+        }
+
+    if (iAllAppsArray)
+        {
+        iAllAppsArray->Reset();
+        delete iAllAppsArray;
+        }
+    
+    delete iXMLParser;
+    delete iDLLParser;
+    delete iDLLElement;
+    delete iBCIssuesBigBuffer;            
+    
+    iWs.Close();
+    iLs.Close();
+    iTimer.Close();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::SetContainerApps(CLauncherContainerApps* aContainerApps)
+    {
+    iContainerApps = aContainerApps;
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::SetContainerOutput(CLauncherContainerOutput* aContainerOutput)
+    {
+    iContainerOutput = aContainerOutput;
+    }
+
+// ---------------------------------------------------------------------------
+
+
+TInt CLauncherEngine::FindFilesRecursiveL(const TDesC& aFileName, const TDesC& aPath)
+    {
+    TInt err = KErrNone;
+    CDirScan* scan = CDirScan::NewLC(iEnv->FsSession());
+    scan->SetScanDataL(aPath, KEntryAttDir, ESortNone);
+    CDir* dirEntries = NULL;
+
+    for(;;)
+        {
+        TRAP(err, scan->NextL(dirEntries));
+        if (!dirEntries  || (err!=KErrNone))
+            break;
+
+        for (TInt i=0; i<dirEntries->Count(); i++) 
+            {
+            TFileName path(scan->FullPath());
+            path.Append((*dirEntries)[i].iName);
+            path.Append(_L("\\"));
+            FindFiles(aFileName, path);
+            }
+        delete(dirEntries);
+        }
+
+    CleanupStack::PopAndDestroy(scan);
+    return err;
+    }
+
+// ---------------------------------------------------------------------------
+
+TInt CLauncherEngine::FindFiles(const TDesC& aFileName, const TDesC& aPath)
+    {
+    TFindFile fileFinder(iEnv->FsSession());
+    CDir* fileList; 
+    TInt err = fileFinder.FindWildByDir(aFileName, aPath, fileList);
+
+    while (err == KErrNone)
+        {
+        for (TInt i=0; i<fileList->Count(); i++)
+            {
+            TParse fullentry;
+            fullentry.Set((*fileList)[i].iName, &fileFinder.File(), NULL);
+
+            TRAP(err, iSystemDllArray->AppendL(fullentry.NameAndExt())); 
+            }
+
+        delete fileList;
+        err = fileFinder.FindWild(fileList);
+        }
+    return err;
+    }
+
+// ---------------------------------------------------------------------------
+
+CDesCArray* CLauncherEngine::ListOfAllAppsL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::ListOfAllAppsL");
+
+    // show wait dialog
+    CAknGlobalNote* waitDialog = CAknGlobalNote::NewLC();
+    waitDialog->SetSoftkeys(R_AVKON_SOFTKEYS_EMPTY);
+    TInt dialogId = waitDialog->ShowNoteL(EAknGlobalWaitNote, _L("Initializing"));
+
+
+    // find all DLLs from the system
+    iSystemDllArray->Reset();
+    TRAP_IGNORE( FindFiles(_L("*.dll"), _L("\\sys\\bin\\")) );
+
+    // write the list of DLLs to a file
+    RFile dllFile;
+    if (dllFile.Replace(iEnv->FsSession(), iSystemDllsFilePath, EFileWrite) == KErrNone)
+        {
+        TBuf8<KMaxFileName> dllName;
+
+        for (TInt i=0; i<iSystemDllArray->MdcaCount(); i++)
+            {
+            dllName.Copy( iSystemDllArray->MdcaPoint(i) );
+            dllName.Append( KFileNewLine );
+
+            dllFile.Write( dllName );
+            }
+
+        dllFile.Close();
+        }
+
+    // reset the apps list
+    iAllAppsArray->Reset();
+
+    // search all apps
+    TApaAppInfo appInfo;
+    iLs.GetAllApps();
+
+    while (iLs.GetNextApp(appInfo) == KErrNone)
+        {
+        iAllAppsArray->AppendL(appInfo.iFullName);
+        }
+
+
+    // remove launcher.app / launcher.exe from the list
+    for (TInt i=0; i<iAllAppsArray->MdcaCount(); i++)
+        {
+        if (iAllAppsArray->MdcaPoint(i).FindF(_L("\\Launcher.")) != KErrNotFound)
+            {
+            iAllAppsArray->Delete(i);
+            iAllAppsArray->Compress();
+            break;
+            }
+        }
+
+    // sort the elements
+    iAllAppsArray->Sort();
+
+    // remove the wait dialog
+    waitDialog->CancelNoteL(dialogId);
+    CleanupStack::PopAndDestroy(); //waitDialog;
+       
+    return iAllAppsArray;
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::StartAppLaunchingL(const CArrayFix<TInt>* aSelectedApps, TBool aAutoClose)
+    {
+    LOGSTRING("Launcher: CLauncherEngine::StartAppLaunchingL");
+
+    // check that we have something to launch
+    if (aSelectedApps->Count() <= 0)
+        {
+        _LIT(message, "Nothing selected");
+        CAknErrorNote* errorNote = new(ELeave) CAknErrorNote;
+        errorNote->ExecuteLD(message);
+        }
+    else
+        {
+        // update the list of applications to be tested
+        iAppsArray->Reset();
+
+        TInt ref(0);
+        TKeyArrayFix key(0, ECmpTUint16);
+        TInt index(0);
+
+        for (TInt i=0; i<iAllAppsArray->MdcaCount(); i++)
+            {
+            ref = i;
+
+            // if the application is selected, append it to the apps array
+            if (aSelectedApps->Find(ref, key, index) == 0)  
+                {
+                iAppsArray->AppendL(iAllAppsArray->MdcaPoint(i));
+                }
+            }
+
+
+        // to make sure that our algorithm works correctly
+        if (iAppsArray->MdcaCount() != aSelectedApps->Count())
+            {
+            _LIT(message, "Something went wrong...");
+            CAknErrorNote* errorNote = new(ELeave) CAknErrorNote;
+            errorNote->ExecuteLD(message);
+            return;
+            }
+
+        
+        // init
+        Cancel();
+        iLaunchingIsActive = ETrue;
+        iAutoClose = aAutoClose;
+        iAppLaunchCounter = 0;
+        iFailedCases = 0;
+        iOkCases = 0;
+        iSkippedCases = 0;
+        iTotalNumberOfCases = iAppsArray->MdcaCount();
+        iCurrentAppUid = KNullUid;
+
+        // open the log file for writing
+        if (iLogFile.Open(iEnv->FsSession(), iLogFilePath, EFileWrite) != KErrNone)
+            {
+            iEnv->FsSession().MkDirAll(iLogFilePath);
+            iLogFile.Replace(iEnv->FsSession(), iLogFilePath, EFileWrite);
+            }
+        else
+            {
+            // file opens correctly, seek to the end
+            TInt fileSize=0;
+            iLogFile.Size(fileSize);
+            iLogFile.Seek(ESeekCurrent, fileSize);
+            }
+
+        ChangeFocusToOutputView();
+
+        iContainerOutput->PrintTextL(_L("New test started.\n"));
+
+        // start the first launch!
+        IssueLaunch();
+
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::IssueLaunch()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::IssueLaunch");
+
+    __ASSERT_ALWAYS(!IsActive(), User::Panic(_L("Timing error?"), 100));
+
+    // this should keep the backlight on
+    User::ResetInactivityTime();
+
+    // some delay
+    iTimer.After(iStatus, 1000000);    
+    SetActive();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::RunL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::RunL");  
+    TInt err = iStatus.Int();
+    User::LeaveIfError(err);
+    
+    if( iDLLAnalysisIsActive )
+        {
+        if( iWaitDialog == 0)
+            {
+            TEntry entry;
+            User::LeaveIfError(iEnv->FsSession().Entry(iRequiredDllsFilePath, entry));
+            TInt fileSize = entry.iSize;
+
+            // init progress bar
+            iWaitDialog = new(ELeave) CAknProgressDialog((reinterpret_cast<CEikDialog**>(&iWaitDialog)), ETrue);
+            iWaitDialog->SetCallback(this);
+            iWaitDialog->PrepareLC(R_GENERAL_PROGRESS_NOTE);
+            iWaitDialog->SetCurrentLabelL( EAknCtNote, _L("Analysing DLLs"));
+            iProgressInfo = iWaitDialog->GetProgressInfoL();
+            iProgressInfo->SetFinalValue( fileSize );
+            iWaitDialog->RunLD();
+            iWaitDialog->MakeVisible( ETrue );
+            }
+        
+        iBCLogFile.Write(iLogWriteBuf->Des());
+        iLogWriteBuf->Des().Zero();
+        return;
+        }
+    else
+        {
+        // write full app path to the log file
+        WriteInitialStuffToTheLogL(iAppsArray->MdcaPoint(iAppLaunchCounter), iLogFile);
+
+        // get the uid of the current app
+        iCurrentAppUid = KNullUid;
+        TApaAppInfo appInfo;
+        iLs.GetAllApps();
+        while (iLs.GetNextApp(appInfo) == KErrNone)
+            {
+            if (appInfo.iFullName.CompareF( iAppsArray->MdcaPoint(iAppLaunchCounter) ) == 0)
+                {
+                iCurrentAppUid = appInfo.iUid;
+                break;
+                }
+            }
+
+        if (iCurrentAppUid == KNullUid)
+            {        
+            iLogWriteBuf->Des().Append(_L("[WARN: App has no UID] "));
+            }
+
+        // parse the filename
+        TParse nameParser;
+        nameParser.SetNoWild(iAppsArray->MdcaPoint(iAppLaunchCounter), NULL, NULL);
+        iCurrentAppNameAndExt.Copy(nameParser.Drive());
+        iCurrentAppNameAndExt.Append(nameParser.NameAndExt());
+
+        // do not try to launch these apps
+        if (iAppsArray->MdcaPoint(iAppLaunchCounter).FindF(_L("\\Launcher.")) != KErrNotFound
+            || iAppsArray->MdcaPoint(iAppLaunchCounter).FindF(_L("\\Phone.")) != KErrNotFound
+            || iAppsArray->MdcaPoint(iAppLaunchCounter).FindF(_L("\\Startup.")) != KErrNotFound  
+            || iAppsArray->MdcaPoint(iAppLaunchCounter).FindF(_L("\\SplashScreen.")) != KErrNotFound  
+            || iAppsArray->MdcaPoint(iAppLaunchCounter).FindF(_L("\\eshell.")) != KErrNotFound)  
+            {
+            iContainerOutput->PrintTextL(iCurrentAppNameAndExt);
+            iContainerOutput->PrintTextL(_L(": SKIPPED automatically\n"));
+
+            iLogWriteBuf->Des().Append(_L("[SKIPPED automatically] "));
+            iLogWriteBuf->Des().Append(KFileNewLine);
+            iLogFile.Write(iLogWriteBuf->Des());
+
+            iSkippedCases++;
+            CheckForMoreAppsL();
+            }
+
+        else
+            {
+
+            // dependency check not needed if the app is in the ROM/ROFS, because they'll be checked automatically
+            // when the rom image is built
+            
+            if (iCurrentAppNameAndExt[0] != 'Z' && iCurrentAppNameAndExt[0] != 'z')
+                {
+
+                if (iCurrentAppNameAndExt[2] == '[')  // this is quite likely a Java application, no dependency test needed 
+                    {
+                    iLogWriteBuf->Des().Append(_L("[Dependency check not done] "));
+                    }
+                else
+                    {  // otherwise check depencies
+                
+                    #ifdef __WINS__
+                    
+                        // emulator not supported
+
+                    #else
+
+                        // ELF binaries
+
+                        CDesCArray* missingDllArray = NULL;
+
+                        TRAPD(err, missingDllArray = DependencyCheckForE32ImageL());
+
+                        // some error happened while processing the E32 image
+                        if (err != KErrNone)
+                            {
+                            iContainerOutput->PrintTextL(iCurrentAppNameAndExt);
+                            iContainerOutput->PrintTextL(_L(": unable to read import table!\n"));
+
+                            iLogWriteBuf->Des().Append(_L("[Unable to read import table!] "));
+                            }
+
+                        // print missing dependencies
+                        else if (err==KErrNone && missingDllArray)
+                            {
+                            if (missingDllArray->MdcaCount() > 0)
+                                {
+                                iContainerOutput->PrintTextL(iCurrentAppNameAndExt);
+                                iContainerOutput->PrintTextL(_L(": missing dependencies: "));
+                                iLogWriteBuf->Des().Append(_L("[Missing dependencies: "));
+
+                                for (TInt k=0; k<missingDllArray->MdcaCount(); k++)
+                                    {
+                                    iContainerOutput->PrintTextL(missingDllArray->MdcaPoint(k));
+                                    iContainerOutput->PrintTextL(_L(" "));
+
+                                    iLogWriteBuf->Des().Append(missingDllArray->MdcaPoint(k));
+                                    iLogWriteBuf->Des().Append(_L(" "));
+                                    }
+
+                                iContainerOutput->PrintTextL(_L("\n"));
+                                iLogWriteBuf->Des().Append(_L("] "));
+                                }
+                            }
+
+                        if (missingDllArray)
+                            delete missingDllArray;
+
+                    #endif
+
+                    }  // if '['
+                }  // if 'Z'
+
+
+
+            // check if the app is already running
+            TApaTaskList taskList(iWs);
+            TApaTask thisTask = taskList.FindApp(iCurrentAppUid);
+            if (thisTask.Exists())
+                {
+                iLogWriteBuf->Des().Append(_L(" [OK: App already running]"));
+                iLogWriteBuf->Des().Append(KFileNewLine);
+                iLogFile.Write(iLogWriteBuf->Des());
+
+                iOkCases++;
+                CheckForMoreAppsL();
+                }
+            
+            else
+                {
+                // check the program's capabilities
+                TApaAppCapabilityBuf buf;
+                iLs.GetAppCapability(buf, iCurrentAppUid);
+                TApaAppCapability cap = buf();
+
+                // if it's embeddable only, don't launch if setting is enabled
+                if (cap.iEmbeddability == TApaAppCapability::EEmbeddableOnly && SkipHiddenAndEmbedOnly())  
+                    {
+                    iContainerOutput->PrintTextL(iCurrentAppNameAndExt);
+                    iContainerOutput->PrintTextL(_L(": SKIPPED: embeddable only\n"));
+
+                    iLogWriteBuf->Des().Append(_L("[SKIPPED: embeddable only] "));
+                    iLogWriteBuf->Des().Append(KFileNewLine);
+                    iLogFile.Write(iLogWriteBuf->Des());
+
+                    iSkippedCases++;
+                    CheckForMoreAppsL();
+                    }
+            
+                // if it's hidden, don't launch if setting is enabled
+                else if (cap.iAppIsHidden && SkipHiddenAndEmbedOnly())  
+                    {
+                    iContainerOutput->PrintTextL(iCurrentAppNameAndExt);
+                    iContainerOutput->PrintTextL(_L(": SKIPPED: hidden\n"));
+
+                    iLogWriteBuf->Des().Append(_L("[SKIPPED: hidden] "));
+                    iLogWriteBuf->Des().Append(KFileNewLine);
+                    iLogFile.Write(iLogWriteBuf->Des());
+
+                    iSkippedCases++;
+                    CheckForMoreAppsL();
+                    }
+
+                // otherwise do the normal launch test
+                else
+                    {
+                    LaunchApplicationL();
+                    }
+                
+                } //if (thisTask.Exists())
+            
+            } //if (iAppsArray->MdcaPoint(iAppLaunchCounter).FindF
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::CheckIfAppIsRunningL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::CheckIfAppIsRunningL");
+
+    // cancel the death notifier since it isn't needed anymore
+    if( iCurrentAppThread.Handle() != 0 )
+        {
+        iCurrentAppThread.LogonCancel(iAppThreadChecker->iStatus);
+        }
+
+    // cancel checkers
+    iAppThreadChecker->Cancel();
+    iAppRunningChecker->Cancel(); 
+
+
+
+    // check from the window server if the app is running
+    TApaTaskList taskList(iWs);
+    TApaTask thisTask = taskList.FindApp(iCurrentAppUid);
+
+    if( !thisTask.Exists() ) // application not running -> FAIL
+        {
+        // check from the thread why it quit
+        CheckWhyThreadDiedL();
+
+        // --> CheckForMoreApps() and all the other stuff called from CheckWhyThreadDied() !
+
+        }
+    else
+        {
+        // app is running!
+        iOkCases++;
+
+        // close handle to the thread        
+        iCurrentAppThread.Close();
+
+
+        iLogWriteBuf->Des().Append(_L(" [OK]"));
+        iLogWriteBuf->Des().Append(KFileNewLine);        
+        iLogFile.Write(iLogWriteBuf->Des());
+
+
+        // close the running application if needed
+        if (iAutoClose)
+            {
+            // since the application is still open, let's close it
+            thisTask.EndTask();
+            //User::After(1000);
+            //thisTask.SendSystemEvent(EApaSystemEventShutdown);
+            //thisTask.KillTask();
+            //User::After(1000);
+            }
+
+        // this app is done now, move to the next one!
+        CheckForMoreAppsL();
+                
+        }    
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::CheckWhyThreadDiedL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::CheckWhyThreadDiedL");
+
+    // cancel the death notifier since it isn't needed anymore
+    if( iCurrentAppThread.Handle() != 0 )
+        {
+        iCurrentAppThread.LogonCancel(iAppThreadChecker->iStatus);
+        }
+
+    // make sure all checkers are cancelled
+    iAppRunningChecker->Cancel(); 
+    iAppThreadChecker->Cancel(); 
+
+    TBuf<256> outputText;
+    outputText.Append(_L("App.Closed. "));
+
+
+    if (iCurrentAppThread.ExitType() == EExitKill)
+        {
+        outputText.Append(_L("\"EExitKill\""));
+        }
+    else if (iCurrentAppThread.ExitType() == EExitTerminate)
+        {
+        outputText.Append(_L("\"EExitTerminate\""));
+        }
+    else if (iCurrentAppThread.ExitType() == EExitPanic)
+        {
+        outputText.Append(_L("\"EExitPanic\""));
+        }
+    else if (iCurrentAppThread.ExitType() == EExitPending)
+        {
+        outputText.Append(_L("\"EExitPending\""));
+        }
+    else // unknown reason
+        {
+        outputText.Append(_L("\"Exit_Unknown_Reason\""));
+        }        
+    
+    outputText.Append(_L(" code:"));
+    TInt exitReason = iCurrentAppThread.ExitReason();
+    outputText.AppendNum(exitReason);
+    outputText.Append(_L(" \""));
+
+    TPtrC exitCategory = iCurrentAppThread.ExitCategory();
+    outputText.Append(exitCategory);
+
+    outputText.Append(_L("\""));
+
+
+    // print to screen
+    iContainerOutput->PrintTextL(iCurrentAppNameAndExt);
+    iContainerOutput->PrintTextL(_L(": "));
+    iContainerOutput->PrintTextL(outputText);
+    iContainerOutput->PrintTextL(_L("\n"));
+
+    // write to the log also
+    iLogWriteBuf->Des().Append(_L(" [FAIL: "));
+    iLogWriteBuf->Des().Append(outputText);
+    iLogWriteBuf->Des().Append(_L("]"));
+    iLogWriteBuf->Des().Append(KFileNewLine);
+    
+    iLogFile.Write(iLogWriteBuf->Des());
+
+    // close handle to the thread
+    //iCurrentAppThread.Close();    <-- not safe the close the handle because of the "App.Closed" dialog
+    //                                  somehow takes ownership of the thread or something
+
+    // nothing to do anymore, move to the next app
+    iFailedCases++;
+    CheckForMoreAppsL();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::CheckForMoreAppsL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::CheckForMoreAppsL");
+
+    // make sure the launcher app is in the foreground
+    TApaTaskList taskList(iWs);
+    TUid launcherAppUid;
+    launcherAppUid.iUid = 0x101FB74F;
+    TApaTask launcherTask = taskList.FindApp(launcherAppUid);
+    launcherTask.BringToForeground();
+
+
+    // check if we have more test to be executed
+    if ( iAppLaunchCounter >= iTotalNumberOfCases-1 )
+        {
+        
+        // all done, show stats
+        TBuf<200> message;
+        message.Append( _L("Done: ") );
+        message.AppendNum( iOkCases );
+        message.Append( _L(" ok, ") );
+        message.AppendNum( iFailedCases );
+        message.Append( _L(" failed, ") );
+        message.AppendNum( iSkippedCases );
+        message.Append( _L(" skipped.") );
+
+        // print the message to the output screen
+        iContainerOutput->PrintTextL(message);
+        iContainerOutput->PrintTextL(_L("\n\n"));
+
+        //write same stuff to the log
+        WriteInitialStuffToTheLogL(message, iLogFile);
+        iLogWriteBuf->Des().Copy(KFileNewLine);
+        iLogWriteBuf->Des().Append(KFileNewLine);        
+        iLogFile.Write(iLogWriteBuf->Des());
+
+        // close the log
+        iLogFile.Close();
+
+        iLaunchingIsActive = EFalse;
+
+        _LIT(KAllDoneMessage, "All apps launched");
+        CAknConfirmationNote* confirmationNote = new(ELeave) CAknConfirmationNote;
+        confirmationNote->ExecuteLD(KAllDoneMessage);
+
+        }
+    else
+        {
+        // more apps to be launched, maintain requests
+        iAppLaunchCounter++;
+        IssueLaunch();
+        }
+  
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::DoCancel()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::DoCancel");
+    
+    if( iXMLParser )
+        {
+        iXMLParser->Cancel();
+        }
+    iTimer.Cancel();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::LaunchApplicationL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::LaunchApplication");
+    LOGSTRING3("Launcher: Trying to launch %S, UID: %d", &iCurrentAppNameAndExt, iCurrentAppUid.iUid);
+
+    TRAPD(err, DoLaunchApplicationL());
+    
+    if (err!=KErrNone)
+        {
+        iLogWriteBuf->Des().Append(_L("[FAIL: Cannot launch the app] "));        
+        
+        iContainerOutput->PrintTextL(iCurrentAppNameAndExt);
+        iContainerOutput->PrintTextL(_L(": cannot launch\n"));
+
+        // write the buffer to the log
+        iLogWriteBuf->Des().Append(KFileNewLine);        
+        iLogFile.Write(iLogWriteBuf->Des());
+
+        // this application isn't even launchable, go to next one
+        iFailedCases++;
+        CheckForMoreAppsL();        
+        }
+    
+    }
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::DoLaunchApplicationL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::DoLaunchApplicationL");
+
+    // create a new handle
+    RThread newThreadHandle;
+    iCurrentAppThread = newThreadHandle;
+
+
+    // Find the task with uid3
+    TApaTaskList tasklist(iWs);
+    TApaTask task=tasklist.FindApp(iCurrentAppUid);
+
+    if (task.Exists())
+        // Task exists, bring it to foreground
+        {
+        task.BringToForeground();
+        }
+    else
+        // Task doesn't exist, launch a new instance of an application
+        {
+        TApaAppInfo appInfo;
+        User::LeaveIfError(iLs.GetAppInfo(appInfo, iCurrentAppUid));
+        TApaAppCapabilityBuf capBuf;
+        User::LeaveIfError(iLs.GetAppCapability(capBuf, iCurrentAppUid));
+        TApaAppCapability& caps = capBuf();
+
+        CApaCommandLine* cmdLine=CApaCommandLine::NewLC();
+        cmdLine->SetExecutableNameL(appInfo.iFullName);
+
+        if ( caps.iLaunchInBackground )
+            // Apps capability defines that the app is launched in background
+            {
+            cmdLine->SetCommandL(EApaCommandBackground);
+            }
+        else
+            {
+            cmdLine->SetCommandL(EApaCommandRun);
+            }
+
+        // start the app
+        User::LeaveIfError(iLs.StartApp(*cmdLine, iCurrentAppThreadId));
+
+        // activate thread checker active object
+        iAppThreadChecker->ActivateChecking();
+
+        // now open a handle to the thread and register death notifier
+        TInt err = iCurrentAppThread.Open(iCurrentAppThreadId);
+        if (err == KErrNone)
+            iCurrentAppThread.Logon(iAppThreadChecker->iStatus);
+        else
+            {
+            iCurrentAppThread.Close();
+            TRequestStatus* status = &iAppThreadChecker->iStatus;
+            User::RequestComplete(status, KErrNone);
+            iAppThreadChecker->Cancel();
+            User::Leave(err);                
+            }
+
+        CleanupStack::PopAndDestroy(); // cmdLine
+        }
+
+    // the application is now running, start a check to see if it's still alive
+    iAppRunningChecker->StartTesting(); 
+
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::StopLaunchingL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::StopLaunchingL");
+
+    //write to the log
+    WriteInitialStuffToTheLogL(_L("Cancelled by the user !!! "), iLogFile);
+    iLogWriteBuf->Des().Copy(KFileNewLine);
+    iLogWriteBuf->Des().Append(KFileNewLine);
+    iLogFile.Write(iLogWriteBuf->Des());
+
+    // close the log
+    iLogFile.Close();
+
+    // print to the screen
+    iContainerOutput->PrintTextL(_L("Launching cancelled.\n\n"));
+
+    // cancel all active objects
+    if( iCurrentAppThread.Handle() != 0 )
+        {
+        iCurrentAppThread.LogonCancel(iAppThreadChecker->iStatus);
+        }
+    Cancel();
+    iAppRunningChecker->Cancel(); 
+    iAppThreadChecker->Cancel(); 
+    
+    iLaunchingIsActive = EFalse;
+
+    _LIT(KMessage, "Launching cancelled");
+    CAknInformationNote* confirmationNote = new(ELeave) CAknInformationNote;
+    confirmationNote->ExecuteLD(KMessage);
+    }
+
+// ---------------------------------------------------------------------------
+
+CDesCArray* CLauncherEngine::DependencyCheckForE32ImageL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::DependencyCheckForE32ImageL");
+
+    // create an empty array for the missing dll names
+    CDesCArray* missingDllArray = new(ELeave) CDesCArrayFlat(100);
+    CleanupStack::PushL(missingDllArray);
+
+    // get a list of DLLs from the E32 image file
+    E32ImageReader* reader = E32ImageReader::NewLC();
+    CDesCArray* dllArray = reader->ListOfDLLsL( iAppsArray->MdcaPoint(iAppLaunchCounter) );
+    CleanupStack::PopAndDestroy(); // reader
+    CleanupStack::PushL(dllArray);
+
+    // compare system DLL and image DLL arrays
+    TInt pos(0);
+    for (TInt j=0; j<dllArray->MdcaCount(); j++)
+        {
+        if (iSystemDllArray->Find(dllArray->MdcaPoint(j), pos, ECmpFolded) != 0)  
+            {
+            // DLL not found, append the name to the list of missing DLLs
+            missingDllArray->AppendL(dllArray->MdcaPoint(j));  
+            }
+        }
+
+    CleanupStack::PopAndDestroy(); // dllArray
+    CleanupStack::Pop();  // missingDllArray
+
+    LOGSTRING("Launcher: CLauncherEngine::DependencyCheckForE32ImageL returns");
+
+    return missingDllArray;
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::WriteInitialStuffToTheLogL(const TDesC& aOwnData, RFile& aFile)
+    {
+    LOGSTRING("Launcher: CLauncherEngine::WriteInitialStuffToTheLog");
+
+    TTime time;
+    time.HomeTime();
+    TBuf<32> currentTime;
+    TBuf<32> currentDate;
+
+    // current date            
+    _LIT(KCurrentDate,"%D%M%Y%/0%1%/1%2%/2%3%/3");
+    time.FormatL(currentDate, KCurrentDate);    
+    iLogWriteBuf->Des().Copy(currentDate);    
+    AppendLogBufferL(KFileSeparator(), iLogWriteBuf);
+
+    // current time
+    _LIT(KCurrentTime,"%-B%:0%J%:1%T%:2%S%:3%+B");
+    time.FormatL(currentTime, KCurrentTime);    
+    AppendLogBufferL(currentTime, iLogWriteBuf);
+    AppendLogBufferL(KFileSeparator(), iLogWriteBuf);
+
+    // available RAM memory
+    TMemoryInfoV1Buf memory;
+    UserHal::MemoryInfo(memory);
+    iLogWriteBuf->Des().AppendNum(memory().iFreeRamInBytes);  
+    AppendLogBufferL(KFileSeparator(), iLogWriteBuf);
+
+    // own data, eg. application name
+    AppendLogBufferL(aOwnData, iLogWriteBuf);
+    AppendLogBufferL(KFileSeparator(), iLogWriteBuf);
+    AppendLogBufferL(KFileNewLine(), iLogWriteBuf);    
+
+    // write the buffer to the file
+    aFile.Write(iLogWriteBuf->Des()); 
+
+    // clear the buffer
+    iLogWriteBuf->Des().Copy(_L(""));
+    }
+
+// ---------------------------------------------------------------------------
+
+TInt CLauncherEngine::DeleteLogFile()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::DeleteLogFile");
+    return BaflUtils::DeleteFile(iEnv->FsSession(), iLogFilePath);
+    }
+
+// ---------------------------------------------------------------------------
+
+TInt CLauncherEngine::DeleteBCLogFile()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::DeleteBCLogFile");
+    return BaflUtils::DeleteFile(iEnv->FsSession(), iBCLogFilePath);
+    }
+
+// ---------------------------------------------------------------------------
+
+TBool CLauncherEngine::LogFileExists()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::LogFileExists");
+    return BaflUtils::FileExists(iEnv->FsSession(), iLogFilePath);
+    }
+
+// ---------------------------------------------------------------------------
+
+TBool CLauncherEngine::BCLogFileExists()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::BCLogFileExists");
+    return BaflUtils::FileExists(iEnv->FsSession(), iBCLogFilePath);
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::DialogDismissedL( TInt aButtonId )
+    {
+    LOGSTRING2("Launcher: CLauncherEngine::DialogDismissedL - Button id: %d", aButtonId);    
+    iWaitDialog = 0;
+    iDLLAnalysisIsActive = EFalse;
+    _LIT(KAnalysisCancelled, "DLL Analysis cancelled");
+    if( IsActive() )
+        {
+        Cancel();
+        }
+    if( iXMLParser )
+        {
+        iXMLParser->Cancel();
+        }
+    if( aButtonId == EAknSoftkeyCancel )
+        {
+        iContainerOutput->PrintTextL( KNewLine );
+        iContainerOutput->PrintTextL( KAnalysisCancelled );
+        iContainerOutput->PrintTextL( KNewLine );
+        if( iLogWriteBuf )
+            {
+            AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+            AppendLogBufferL(KAnalysisCancelled(), iLogWriteBuf);
+            AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+            if( iBCLogFile.SubSessionHandle() != 0)
+                {
+                iBCLogFile.Write(iLogWriteBuf->Des());
+                }
+            iLogWriteBuf->Des().Zero();
+            }
+        iBCLogFile.Close();
+        }        
+    }
+
+// ---------------------------------------------------------------------------
+
+TBool CLauncherEngine::SelectRequiredDLLsFileL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::SelectRequiredDLLsFile");
+    _LIT(KMessage, "Please, select input file for BC analysis");
+    CAknInformationNote* infoNote = new(ELeave) CAknInformationNote(ETrue);
+    infoNote->ExecuteLD(KMessage);    
+    return AknCommonDialogs::RunSelectDlgLD( iRequiredDllsFilePath, R_MEMORY_SELECTION_DIALOG, R_FILE_SELECTION_DIALOG);
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::DoBCAnalysisL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::DoBCAnalysisL");
+    if( iXMLParser == 0 )
+        {
+        iXMLParser = CLauncherXMLParser::NewL(iEnv->FsSession());
+        }
+    
+    delete iWaitDialog;
+    iWaitDialog = 0;    
+    iXMLParser->ParseL(iRequiredDllsFilePath,this);
+    iDLLAnalysisIsActive = ETrue;
+    
+    // some delay
+    iTimer.After(iStatus, 500000);
+    SetActive();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::AnalyseDLLsL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::AnalyseDLLsL");
+    _LIT(KStartSeparator, "******************************");
+    _LIT(KStartingAnalysis, "Starting BC Analysis for DLLs.");    
+    _LIT(KInputFileSelected, "Input file selected: ");
+    
+    // Reset found issues counter and buffer
+    iFoundBCIssues = 0;    
+    delete iBCIssuesBigBuffer;
+    iBCIssuesBigBuffer = 0;
+    
+    // Reset log writing buffer:
+    iLogWriteBuf->Des().Zero();
+                
+    if( IsActive() )
+        {
+        Cancel();
+        }           
+   
+    if( !SelectRequiredDLLsFileL() )
+        {        
+        return; // Input file selection cancelled
+        }
+    
+    // open the log file for writing
+    if (iBCLogFile.Open(iEnv->FsSession(), iBCLogFilePath, EFileWrite) != KErrNone)
+        {
+        iEnv->FsSession().MkDirAll(iLogFilePath);
+        iBCLogFile.Replace(iEnv->FsSession(), iBCLogFilePath, EFileWrite);
+        }
+    else
+        {
+        // file opens correctly, seek to the end
+        TInt fileSize=0;
+        iBCLogFile.Size(fileSize);
+        iBCLogFile.Seek(ESeekCurrent, fileSize);
+        }
+    
+    AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+    AppendLogBufferL(KStartSeparator(), iLogWriteBuf);
+    AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+    iBCLogFile.Write(iLogWriteBuf->Des());
+    iLogWriteBuf->Des().Zero();
+    
+    // Resolve file type. Should we use XML parsing or just compare DLL list
+    TBool xmlParsing =
+        KDotXML().Compare(iRequiredDllsFilePath.Right(KDotXML().Length())) == 0 ||
+        KDotLauncherXML().Compare(iRequiredDllsFilePath.Right(KDotLauncherXML().Length())) == 0;
+    
+    // Log analysis starting time and selected input file:
+    WriteInitialStuffToTheLogL(KStartingAnalysis, iBCLogFile);    
+    AppendLogBufferL(KInputFileSelected(), iLogWriteBuf);
+    AppendLogBufferL(iRequiredDllsFilePath, iLogWriteBuf);
+    AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+    iBCLogFile.Write(iLogWriteBuf->Des());
+    iLogWriteBuf->Des().Zero();
+    
+    if( xmlParsing )
+        {
+        ChangeFocusToOutputView();
+        DoBCAnalysisL();
+        }
+    else
+        {
+        DoCompareDLLListsL();
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::DoCompareDLLListsL()
+    {
+    LOGSTRING("Launcher: CLauncherEngine::DoCompareDLLListsL");
+    RFile file;
+    CleanupClosePushL(file);
+    
+    if(file.Open(iEnv->FsSession(), iRequiredDllsFilePath, EFileRead) != KErrNone)
+        {
+        ChangeFocusToOutputView();
+
+        TBuf<200> msg;
+        msg.Format(_L("Unable to open %S for reading!\n\n"), &iRequiredDllsFilePath);
+        iContainerOutput->PrintTextL( msg );
+        }
+    else
+        {
+        CDesCArray* requiredDllArray = new(ELeave) CDesCArrayFlat(KMaxDllArraySize);
+        CleanupStack::PushL(requiredDllArray);
+
+        // read all lines the text file
+        TFileName dllName;
+        TInt i(0);
+        while( ReadLineFromFileL(file, dllName) == KErrNone && i<KMaxDllArraySize )
+            {
+            dllName.TrimAll();
+
+            if (dllName.Length() > 1)
+                requiredDllArray->AppendL(dllName);
+            
+            i++;
+            }
+
+        if (requiredDllArray->MdcaCount() == 0)
+            {
+            ChangeFocusToOutputView();
+
+            TBuf<200> msg;
+            msg.Format(_L("File %S is empty!\n\n"), &iRequiredDllsFilePath);
+            iContainerOutput->PrintTextL( msg );
+            }
+        else
+            {
+            // compare the arrays and print any missing items
+            CDesCArray* missingDllArray = new(ELeave) CDesCArrayFlat(KMaxDllArraySize);
+            CleanupStack::PushL(missingDllArray);
+
+            TInt pos(0);
+            for (TInt j=0; j<requiredDllArray->MdcaCount(); j++)
+                {
+                if (iSystemDllArray->Find(requiredDllArray->MdcaPoint(j), pos, ECmpFolded) != 0)  
+                    {
+                    // DLL not found, append the name to the list of missing DLLs
+                    missingDllArray->AppendL(requiredDllArray->MdcaPoint(j));  
+                    }
+                }
+
+            if (missingDllArray->MdcaCount() == 0)
+                {
+                _LIT(KMessage, "No missing files found");
+                AppendLogBufferL(KMessage(), iLogWriteBuf);
+                CAknInformationNote* note = new(ELeave) CAknInformationNote;
+                note->ExecuteLD(KMessage);
+                }
+            else
+                {
+                ChangeFocusToOutputView();
+                _LIT(KMissingFiles, "Missing files:\n");
+
+                iContainerOutput->PrintTextL( KMissingFiles );
+                AppendLogBufferL(KMissingFiles(), iLogWriteBuf);
+                
+                for (TInt i=0; i<missingDllArray->MdcaCount(); i++)
+                    {
+                    iContainerOutput->PrintTextL( missingDllArray->MdcaPoint(i) );                    
+                    iContainerOutput->PrintTextL( _L("\n") );           
+                    AppendLogBufferL(missingDllArray->MdcaPoint(i), iLogWriteBuf);
+                    AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+                    }
+
+                iContainerOutput->PrintTextL( _L("\n") );
+                }
+
+            CleanupStack::PopAndDestroy(); // missingDllArray            
+            }
+
+        CleanupStack::PopAndDestroy(); // requiredDllArray
+        }
+
+    CleanupStack::PopAndDestroy(); //file
+    iBCLogFile.Write(iLogWriteBuf->Des());
+    iLogWriteBuf->Des().Zero();
+    iBCLogFile.Close();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::ParsingProgressedL(TInt aBytes)
+    {
+    LOGSTRING2("Launcher: CLauncherEngine::ParsingProgressedL - Bytes: %d", aBytes);
+    if (iProgressInfo && aBytes > 0 )
+        {
+        iProgressInfo->SetAndDraw(aBytes);
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::DocumentParsedL(TInt aErrorCode)
+    {            
+    LOGSTRING2("Launcher: CLauncherEngine::DocumentParsedL (Error code: %d)", aErrorCode);
+        
+    iDLLAnalysisIsActive = EFalse;
+    _LIT(KParseError, "Parse error: ");
+    _LIT(KNoIssues, "No binary compatibility issues found");
+    
+    if( IsActive() )
+        {
+        Cancel();
+        }
+            
+    if( iWaitDialog )
+        {
+        iWaitDialog->ProcessFinishedL();
+        iWaitDialog = 0;
+        }
+        
+    if( aErrorCode != KErrNone )
+        {
+        TBuf<16> errorCodeString;
+        errorCodeString.AppendNum(aErrorCode);
+        iContainerOutput->PrintTextL( KNewLine );
+        iContainerOutput->PrintTextL( KParseError );
+        iContainerOutput->PrintTextL( errorCodeString );
+        iContainerOutput->PrintTextL( KNewLine );        
+        AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+        AppendLogBufferL(KParseError(), iLogWriteBuf);
+        AppendLogBufferL(errorCodeString, iLogWriteBuf);
+        AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+        }
+    else if(iFoundBCIssues == 0)
+        {
+        iContainerOutput->PrintTextL( KNoIssues );
+        iContainerOutput->PrintTextL( KNewLine );        
+        AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+        AppendLogBufferL(KNoIssues(), iLogWriteBuf);
+        AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+        }
+    else if( iBCIssuesBigBuffer && iBCIssuesBigBuffer->Des().Length() > 0 )
+        {
+        iContainerOutput->PrintTextL(iBCIssuesBigBuffer->Des());
+        delete iBCIssuesBigBuffer;
+        iBCIssuesBigBuffer = 0;
+        }
+    if( iLogWriteBuf->Length() > 0 && iBCLogFile.SubSessionHandle() != 0)
+        {
+        iBCLogFile.Write(iLogWriteBuf->Des());
+        }
+    WriteInitialStuffToTheLogL(_L("Analysis ready"), iBCLogFile);
+    iLogWriteBuf->Des().Zero();
+    iBCLogFile.Close();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::ElementParsedL(const CLauncherDLLElement& aDllElement)
+    {
+    LOGSTRING("Launcher: CLauncherEngine::ElementParsedL");
+    User::ResetInactivityTime();
+    _LIT(KNewLine, "\n");
+    _LIT(KIndent, "    ");
+    _LIT(KIssuesFound, "Binary compatibility issues found:"); 
+    _LIT(KDLLMissing,"DLL is missing");
+    _LIT(KUID1Changed,"UID1 changed");
+    _LIT(KUID2Changed,"UID2 changed");
+    _LIT(KUID3Changed,"UID3 changed");
+    _LIT(KSIDChanged,"SID changed");
+    _LIT(KCapabilityChanged,"Capability changed");
+    
+    if( iDLLElement == 0 )
+        {
+        iDLLElement = CLauncherDLLElement::NewL();
+        }
+    
+    TFindFile fileFinder(iEnv->FsSession());
+    _LIT(KDLLPath, "\\sys\\bin\\");
+    TInt err = fileFinder.FindByPath(aDllElement.Name(), &KDLLPath); 
+    
+    TBuf<256> issueStr;
+    
+    if( err == KErrNotFound )
+        {
+        if( iFoundBCIssues++ == 0 )
+            {                        
+            iContainerOutput->PrintTextL( KIssuesFound );
+            iContainerOutput->PrintTextL( KNewLine );            
+            AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+            AppendLogBufferL(KIssuesFound(), iLogWriteBuf);
+            AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+            }
+        issueStr.Copy(aDllElement.Name());
+        issueStr.Append(KNewLine);
+        issueStr.Append(KIndent);
+        issueStr.Append(KDLLMissing);
+        issueStr.Append(KNewLine);
+                
+        AppendLogBufferL(issueStr, iLogWriteBuf);
+        
+        TFileName dllName = aDllElement.Name();
+        LOGSTRING2("Launcher: DLL not found: %S", &dllName);
+        if( iFoundBCIssues > KBigBufferUsageThreshold )
+            {
+            if( iBCIssuesBigBuffer == 0)
+                {
+                iBCIssuesBigBuffer = HBufC::NewL(KBigBufferAllocBytes);
+                }
+            TInt maxSize = iBCIssuesBigBuffer->Des().Length() + issueStr.Length();
+            if( maxSize >= iBCIssuesBigBuffer->Des().MaxLength())
+                {
+                iBCIssuesBigBuffer = iBCIssuesBigBuffer->ReAllocL(maxSize + KBigBufferAllocBytes );                
+                }
+            TPtr ptr(iBCIssuesBigBuffer->Des());
+            ptr += issueStr;            
+            }
+        else
+            {
+            iContainerOutput->PrintTextL( issueStr);
+            }
+        }
+    else if( err == KErrNone)
+        {
+        // File is found, so let's try to open it:
+        RFile dllFile;
+        CleanupClosePushL(dllFile);        
+        if( dllFile.Open(iEnv->FsSession(), fileFinder.File(), EFileRead) == KErrNone )
+            {
+            // Parse DLL:
+            iDLLParser->ParseL(iEnv->FsSession(), dllFile, *iDLLElement);
+            CleanupStack::PopAndDestroy(); // dllFile            
+            RArray<CLauncherDLLElement::TDifference> diffs;
+            CleanupClosePushL(diffs);
+                        
+            // Compare DLLs:              
+            if( iDLLElement->CompareL(aDllElement, diffs))
+                {                
+                if( iFoundBCIssues++ == 0 )
+                    {
+                    iContainerOutput->PrintTextL( KIssuesFound );
+                    iContainerOutput->PrintTextL( KNewLine );                   
+                    AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+                    AppendLogBufferL(KIssuesFound(), iLogWriteBuf);
+                    AppendLogBufferL(KFileNewLine(), iLogWriteBuf);
+                    }
+                // Differencies found:
+                for( TInt i = 0; i < diffs.Count(); ++i )
+                    {                
+                    // Print DLL name:
+                    if( i == 0 )
+                        {
+                        issueStr.Copy(aDllElement.Name());
+                        issueStr.Append(KNewLine);
+                        }
+                    
+                    // Print differencies:
+                    issueStr.Append(KIndent);
+                    switch(diffs[i])
+                        {
+                        case CLauncherDLLElement::EDifference_UID1:
+                            issueStr.Append(KUID1Changed);
+                            break;
+                        case CLauncherDLLElement::EDifference_UID2:
+                            issueStr.Append( KUID2Changed );
+                            break;
+                        case CLauncherDLLElement::EDifference_UID3:
+                            issueStr.Append( KUID3Changed );
+                            break;
+                        case CLauncherDLLElement::EDifference_SID:
+                            issueStr.Append( KSIDChanged );
+                            break;
+                        case CLauncherDLLElement::EDifference_Capability:
+                            issueStr.Append( KCapabilityChanged );
+                            break;
+                        }
+                    issueStr.Append( KNewLine );                    
+                    }
+                AppendLogBufferL(issueStr, iLogWriteBuf);
+                if( iFoundBCIssues > KBigBufferUsageThreshold )
+                    {
+                    // To improve performance, don't print issues to output anymore.
+                    // Instead, store the issues in buffer and print them when analysis is done.
+                    if( iBCIssuesBigBuffer == 0)
+                        {
+                        iBCIssuesBigBuffer = HBufC::NewL(KBigBufferAllocBytes);
+                        }
+                    TInt maxSize = iBCIssuesBigBuffer->Des().Length() + issueStr.Length();
+                    if( maxSize >= iBCIssuesBigBuffer->Des().MaxLength())
+                        {
+                        TInt increaseSize = Max(issueStr.Length(), KBigBufferAllocBytes);
+                        iBCIssuesBigBuffer = iBCIssuesBigBuffer->ReAllocL(maxSize + increaseSize );                            
+                        }
+                    TPtr ptr(iBCIssuesBigBuffer->Des());
+                    ptr += issueStr;
+                    }
+                else
+                    {
+                    iContainerOutput->PrintTextL( issueStr);
+                    }
+                }
+            CleanupStack::Pop(); // diffs
+            diffs.Close();            
+            }
+        else
+            {
+            CleanupStack::PopAndDestroy(); // dllFile
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+
+TInt CLauncherEngine::ReadLineFromFileL(RFile& aFile, TDes& aReadBuf)
+    {
+    LOGSTRING("Launcher: CLauncherEngine::ReadLineFromFile");
+
+    _LIT8(KImcvCRLF, "\r\n");
+    TInt err(KErrNone);
+
+    HBufC8* tempLine = HBufC8::NewLC(1000);
+    TPtr8 buffer = tempLine->Des();
+
+    // clear the target buffer
+    aReadBuf.Zero();
+
+    // get the current file position
+    TInt filePos(0);
+    aFile.Seek(ESeekCurrent, filePos);
+
+    // read the buffer
+    err = aFile.Read(buffer);
+
+    // check if it's the end of file
+    TInt s = buffer.Length();
+    if (s == 0)
+        err = KErrEof;
+
+    if (err == KErrNone)
+        {
+        // copy to the lfcr and then set the file pointer to the point after that
+        TInt pos = buffer.Find(KImcvCRLF);
+        if (pos != -1)
+            {
+            TFileName tempBuf;
+            buffer.SetLength(pos);
+            tempBuf.Copy(buffer);
+            aReadBuf.Justify(tempBuf, pos, ELeft, ' ');
+            filePos += (pos+2);
+
+            // set the file pointer back to after the lfcr
+            aFile.Seek(ESeekStart, filePos);
+            }
+        
+        // else fill the whole buffer
+        else
+            {
+            aReadBuf.Copy(buffer);
+            }
+        }
+
+    CleanupStack::PopAndDestroy(); // tempLine
+    return err;
+    }
+
+// ---------------------------------------------------------------------------
+
+#if ( SYMBIAN_VERSION_SUPPORT < SYMBIAN_4 )
+void CLauncherEngine::SendLogViaSendUiL(CSendUi* aSendUi)
+    {
+    LOGSTRING("Launcher: CLauncherEngine::SendLogViaSendUiL");
+
+    CMessageData* messageData = CMessageData::NewL();
+    CleanupStack::PushL( messageData );
+    if( LogFileExists() )
+        {
+        messageData->AppendAttachmentL( iLogFilePath );
+        }
+    if( BCLogFileExists() )
+        {
+        messageData->AppendAttachmentL( iBCLogFilePath );
+        }
+    aSendUi->ShowQueryAndSendL( messageData, TSendingCapabilities(0, 0, TSendingCapabilities::ESupportsAttachments ));
+    CleanupStack::PopAndDestroy(); //messageData
+    }
+#endif
+
+// ---------------------------------------------------------------------------
+
+#if ( SYMBIAN_VERSION_SUPPORT < SYMBIAN_4 )
+void CLauncherEngine::SendListOfSystemDllsViaSendUiL(CSendUi* aSendUi)
+    {
+    LOGSTRING("Launcher: CLauncherEngine::SendListOfDllsViaSendUiL");
+
+    if (BaflUtils::FileExists(iEnv->FsSession(), iSystemDllsFilePath))
+        {
+        CMessageData* messageData = CMessageData::NewL();
+        CleanupStack::PushL( messageData );
+        messageData->AppendAttachmentL( iSystemDllsFilePath );
+        aSendUi->ShowQueryAndSendL( messageData, TSendingCapabilities(0, 0, TSendingCapabilities::ESupportsAttachments ));
+        CleanupStack::PopAndDestroy(); //messageData
+        }
+    else
+        {
+        _LIT(message, "DLL list does not exist");
+        CAknErrorNote* errorNote = new(ELeave) CAknErrorNote;
+        errorNote->ExecuteLD(message);        
+        }
+    }
+#endif
+
+// ---------------------------------------------------------------------------
+
+void CLauncherEngine::ChangeFocusToOutputView()
+    {
+    iAppUi->TabGroup()->SetActiveTabByIndex( 1 );
+    TRAP_IGNORE(iAppUi->ActivateLocalViewL( KView2Id ));
+    }
+
+
+// ---------------------------------------------------------------------------
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+// ---------------------------------------------------------------------------
+
+CAppRunningChecker* CAppRunningChecker::NewL(CLauncherEngine* aLauncherEngine)
+    {
+    LOGSTRING("Launcher: CAppRunningChecker::NewL");
+
+    CAppRunningChecker* self = new(ELeave) CAppRunningChecker;
+    CleanupStack::PushL(self);
+    self->ConstructL(aLauncherEngine);
+    CleanupStack::Pop();
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+
+CAppRunningChecker::CAppRunningChecker() : CActive(EActivePriorityIpcEventsHigh)
+    {
+    }
+
+// ---------------------------------------------------------------------------
+
+void CAppRunningChecker::ConstructL(CLauncherEngine* aLauncherEngine)
+    {
+    LOGSTRING("Launcher: CAppRunningChecker::ConstructL");
+
+    iEnv = CEikonEnv::Static();
+    User::LeaveIfError(iTimer.CreateLocal());
+
+    iLauncherEngine = aLauncherEngine;
+
+    CActiveScheduler::Add(this);
+    }
+
+// ---------------------------------------------------------------------------
+
+CAppRunningChecker::~CAppRunningChecker()
+    {
+    LOGSTRING("Launcher: CAppRunningChecker::~CAppRunningChecker");
+
+    Cancel();
+
+    iTimer.Close();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CAppRunningChecker::StartTesting()
+    {
+    LOGSTRING("Launcher: CAppRunningChecker::StartTesting");
+
+    __ASSERT_ALWAYS(!IsActive(), User::Panic(_L("Running Checker"), 200));
+
+    // async delay of seven seconds
+    iTimer.After(iStatus, 7000000);    
+    SetActive();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CAppRunningChecker::RunL()
+    {
+    LOGSTRING("Launcher: CAppRunningChecker::RunL");
+
+    // check if the application is running
+    iLauncherEngine->CheckIfAppIsRunningL();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CAppRunningChecker::DoCancel()
+    {
+    LOGSTRING("Launcher: CAppRunningChecker::DoCancel");
+    iTimer.Cancel();
+    }
+
+// ---------------------------------------------------------------------------
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+// ---------------------------------------------------------------------------
+
+CAppThreadChecker* CAppThreadChecker::NewL(CLauncherEngine* aLauncherEngine)
+    {
+    LOGSTRING("Launcher: CAppThreadChecker::NewL");
+
+    CAppThreadChecker* self = new(ELeave) CAppThreadChecker;
+    CleanupStack::PushL(self);
+    self->ConstructL(aLauncherEngine);
+    CleanupStack::Pop();
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+
+CAppThreadChecker::CAppThreadChecker() : CActive(EActivePriorityIpcEventsHigh)
+    {
+    }
+
+// ---------------------------------------------------------------------------
+
+void CAppThreadChecker::ConstructL(CLauncherEngine* aLauncherEngine)
+    {
+    LOGSTRING("Launcher: CAppThreadChecker::ConstructL");
+
+    iEnv = CEikonEnv::Static();
+
+    iLauncherEngine = aLauncherEngine;
+
+    CActiveScheduler::Add(this);
+    }
+
+// ---------------------------------------------------------------------------
+
+CAppThreadChecker::~CAppThreadChecker()
+    {
+    LOGSTRING("Launcher: CAppThreadChecker::~CAppThreadChecker");
+
+    Cancel();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CAppThreadChecker::ActivateChecking()
+    {
+    LOGSTRING("Launcher: CAppThreadChecker::ActivateChecking");
+
+    __ASSERT_ALWAYS(!IsActive(), User::Panic(_L("Thread Checker"), 300));
+
+    SetActive();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CAppThreadChecker::RunL()
+    {
+    LOGSTRING("Launcher: CAppThreadChecker::RunL");
+
+    // check the state of the thread
+    iLauncherEngine->CheckWhyThreadDiedL();
+    }
+
+// ---------------------------------------------------------------------------
+
+void CAppThreadChecker::DoCancel()
+    {
+    LOGSTRING("Launcher: CAppThreadChecker::DoCancel");
+    }
+
+// ---------------------------------------------------------------------------
+