diff -r f5050f1da672 -r 04becd199f91 javatools/javaappbackconverter/src.s60/backconverter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javatools/javaappbackconverter/src.s60/backconverter.cpp Tue Apr 27 16:30:29 2010 +0300 @@ -0,0 +1,570 @@ +/* +* 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: Java platform 2.0 javaappbackconverter process. +* Reregisters the old S60 MIDlets back to AppArc +* +*/ + + +#include +#include +#include +#include + +#include "javacommonutils.h" +#include "javauids.h" +#include "backconverter.h" +#include "noarmlogs.h" + + +const TInt KDelayWhenWaitingAppArc = 500000; + +// This is in the private data cage of javaappbackconverter +_LIT(KMidletImportDirectory, "C:\\private\\20022D90\\data\\"); + +// Symbian file path separator +_LIT(KPathSeperator, "\\"); + +// Postfix for the fake application name generated only to make AppArc happy +_LIT(KAppPostfix, ".fakeapp"); + +// The application type Uid for MIDlets in S60 +const TUid KUidMidletApplicationType = { 0x10210E26 }; + +/** + * To create new instance of this class. + * + * @param aFs - A reference to the file server. + * @return Reference to the object of this class. + * @exception If construction fails. + * + */ +CBackConverter* CBackConverter::NewLC(RFs& aFs) +{ + CBackConverter* self = new(ELeave) CBackConverter(aFs); + CleanupStack::PushL(self); + self->ConstructL(); + return self; +} + +/** + * To do 1st phase construction for this object. + * + * Adds this active object to the scheduler. + * + * @param param aFs - A reference to the file server. + * @return Reference to the object of this class. + */ +CBackConverter::CBackConverter(RFs& aFs) : + CActive(EPriorityStandard), iFs(aFs) +{ + CActiveScheduler::Add(this); +} + +/** + * To do 2nd phase construction for this object. + * + * @exception If the method is not able to allocate necessary buffers. + */ +void CBackConverter::ConstructL() +{ + JELOG2(EJavaConverters); + + iMidlets = new(ELeave) CMidletList(); + iState = EInitialize; +} + +/** + * Deletes this object. + * All allocated resources are released. + */ +CBackConverter::~CBackConverter() +{ + JELOG2(EJavaConverters); + Cancel(); + if (iMidlets) + { + iMidlets->ResetAndDestroy(); + delete iMidlets; + iMidlets = NULL; + } +} + +/** + * To start back conversion + */ +void CBackConverter::Start() +{ + JELOG2(EJavaConverters); + iState = EInitialize; + CompleteRequest(); +} + +/** + * To stop whole back conversion. + * Stops the active scheduler. + */ +void CBackConverter::Exit() +{ + Deque(); + CActiveScheduler::Stop(); +} + +/** + * To complete the request for this object. + * + * @Postconditions The following conditions are true immediately after + * returning from this method. + * - iStatus == KErrNone + * - IsActive() == ETrue + */ +void CBackConverter::CompleteRequest() +{ + JELOG2(EJavaConverters); + + TRequestStatus *status = &iStatus; + User::RequestComplete(status, KErrNone); + if (!IsActive()) + { + SetActive(); + } +} + +/** + * To run this active object. + * + * The state logic is: + * + * EInitialize: + * - if midlet export data file does not exist, exit + * + * EReadConversionData: + * - read data from data file to iMidlets + * + * EReregisterMidlets: + * - register each midlet in iMidlets to AppArc + * + * EExit: + * - free resources and exit + * + */ +void CBackConverter::RunL() +{ + JELOG2(EJavaConverters); + + switch (iState) + { + + case EInitialize: + { + LOG(EJavaConverters, EInfo, + "CBackConverter::RunL EInitialize"); + + TFileName dataFile(KMidletImportDirectory); + dataFile.Append(KMidletExportDataFileName); + TUint attributes; + TInt err = iFs.Att(dataFile, attributes); + if (KErrNone != err) + { + WLOG1(EJavaConverters, + "CBackConverter::RunL EInitialize " + "Data file does not exist (%d). Cannot do back conversion.", err); + LOG1WSTR(EJavaConverters, EInfo, + "Data file name is %s", (wchar_t *)(dataFile.PtrZ())); + iState = EExit; + } + else + { + iState = EReadConversionData; + } + CompleteRequest(); + } + break; + + case EReadConversionData: + { + LOG(EJavaConverters, EInfo, + "CBackConverter::RunL EReadConversionData"); + + // Read all midlet info from data file to iMidlets + TFileName importDirectory(KMidletImportDirectory); + iMidlets->ImportListL(iFs, importDirectory); + + iState = EUnregisterOldMidletData; + CompleteRequest(); + } + break; + + case EUnregisterOldMidletData: + { + LOG(EJavaConverters, EInfo, + "CBackConverter::RunL EUnregisterOldMidletData"); + + // If executing backconverter after user cancel, + // AppArc may contain Java 2.0 specific data + // for converted midlets. Remove it or reregistration + // will not update the data. + UnregisterOldMidletData(); + + iState = EReregisterMidlets; + CompleteRequest(); + } + break; + + case EReregisterMidlets: + { + LOG(EJavaConverters, EInfo, + "CBackConverter::RunL EReregisterMidlets"); + + // Reregister old midlet info back to AppArc + RegisterMidletsL(); + + // If this line is executed, registering old midlets + // back to AppArc succeeded. So the data file can be + // removed. + RemoveDataFile(); + + iState = EExit; + CompleteRequest(); + } + break; + + case EExit: + { + LOG(EJavaConverters, EInfo, "CBackConverter::RunL EExit"); + + FullCleanup(); + + // The whole javaappbackconverter process is stopped. + Exit(); + } + break; + + } +} + +/** + * To handle leave from RunL. + * This method exits this active object using normal state machine + * After calling this method this active object will exit. + * + * @param aError - A reason of error. + * @return KErrNone. + */ +TInt CBackConverter::RunError(TInt aError) +{ + ELOG2(EJavaConverters, + "CBackConverter::RunError(%d) from state %d", aError, iState); + + Cancel(); + + iState = EExit; + CompleteRequest(); + + return KErrNone; +} + +/** + * To do cancelling for this object. + * + */ +void CBackConverter::DoCancel() +{ + ELOG1(EJavaConverters, + "CBackConverter::DoCancel from state %d", iState); + +} + +/** + * To cleanup member variables. + */ +void CBackConverter::FullCleanup() +{ + JELOG2(EJavaPreinstaller); + + if (iMidlets) + { + iMidlets->ResetAndDestroy(); + delete iMidlets; + iMidlets = NULL; + } +} + +/** + * Register all midlets in iMidlets to AppArc. + */ +void CBackConverter::RegisterMidletsL() +{ + RApaLsSession apaSession; + + // open AppArc session + TInt err = apaSession.Connect(); + if (KErrNone != err) + { + // Cannot connect to AppArc server + ELOG(EJavaConverters, + "CBackConverter::RegisterMidletsL: Cannot connect to AppArc server"); + User::Leave(err); + } + CleanupClosePushL(apaSession); + + // Delete any pending (un)registrations (possible if + // e.g. device rebooted before commit). + // This call does nothing if there is no pending registrations. + // Ignore errors. + (void)apaSession.RollbackNonNativeApplicationsUpdates(); + + // Prepare for Java application registrations / unregistrations + TRAP(err, apaSession.PrepareNonNativeApplicationsUpdatesL()); + if (KErrNone != err) + { + ELOG1(EJavaConverters, + "CBackConverter::RegisterMidletsL: " + "PrepareNonNativeApplicationsUpdatesL leaved with err %d", + err); + User::Leave(err); + } + + // register midlets one by one + CMidletInfo *midlet = iMidlets->GetFirst(); + TBuf8<512> midletDesc; + + while (NULL != midlet) + { + midlet->ToString8(midletDesc); + WLOG(EJavaConverters, + "CBackConverter::RegisterMidletsL Going to reregister this midlet:"); + midletDesc.ZeroTerminate(); + WLOG(EJavaPreinstaller, (const char *)(midletDesc.Ptr())); + midletDesc.Zero(); + + RegisterOneMidletL(&apaSession, midlet); + midlet = iMidlets->GetNext(); + } + + // commit registrations + TRAP(err, apaSession.CommitNonNativeApplicationsUpdatesL()); + if (KErrNone != err) + { + ELOG1(EJavaConverters, + "CBackConverter::RegisterMidletsL: " + "CommitNonNativeApplicationsUpdatesL leaved with err %d", + err); + User::Leave(err); + } + + CleanupStack::PopAndDestroy(); // apaSession +} + +/** + * Register one midlet to AppArc + * + * @param aSession AppArc session + * @param aMidlet the midlet to be registered + * @exception If registering application fails + */ +void CBackConverter::RegisterOneMidletL(RApaLsSession *aSession, CMidletInfo *aMidlet) +{ + JELOG2(EJavaPreinstaller); + + RFile appArcIcon; + TInt numberOfIcons = 1; + + // open the icon in the shared mode required by AppArc + TInt err = appArcIcon.Open( + iFs, + aMidlet->GetIconFileName(), + (EFileShareReadersOrWriters | EFileWrite)); + if (KErrNone != err) + { + ELOG1(EJavaConverters, + "CBackConverter::RegisterOneMidletL: Cannot open icon, err code is %d ", + err); + User::Leave(err); + } + + // Now icon is open + CleanupClosePushL(appArcIcon); + + // Generate the executable name name using the same + // algorithm as used earlier in S60 platform + // in case some external S60 application + // needs to parse the Uid from the executable name. + TFileName appName; + appName.Copy(KPathSeperator); + appName.AppendNum(aMidlet->GetMidletUid().iUid); + appName.Append(KAppPostfix); + + // Create writer needed for actual registration + CApaRegistrationResourceFileWriter *writer = NULL; + writer = + CApaRegistrationResourceFileWriter::NewL( + aMidlet->GetMidletUid(), + appName, + TApaAppCapability::ENonNative); + CleanupStack::PushL(writer); + + writer->SetGroupNameL(aMidlet->GetGroupName()); + + // Write MIDlet suite id and MIDlet id to opaque data (needed by S60 MIDlet launcher) + TBuf8<8> opaqueData; // opaque data will contain two signed 32-bit int + RDesWriteStream writeStream(opaqueData); + writeStream.WriteInt32L(aMidlet->GetSuiteId()); + writeStream.WriteInt32L(aMidlet->GetMidletId()); + writeStream.CommitL(); + writer->SetOpaqueDataL(opaqueData); + + CApaLocalisableResourceFileWriter* lWriter = NULL; + lWriter = + CApaLocalisableResourceFileWriter::NewL( + KNullDesC, // short caption + aMidlet->GetMidletName(), // caption + numberOfIcons, + KNullDesC); + CleanupStack::PushL(lWriter); + + TDriveUnit targetDrive(aMidlet->GetDrive()); + + // Register application to AppArc + aSession->RegisterNonNativeApplicationL( + KUidMidletApplicationType, + targetDrive, + *writer, + lWriter, + &appArcIcon); + + CleanupStack::PopAndDestroy(lWriter); + CleanupStack::PopAndDestroy(writer); + // close icon file handle + CleanupStack::PopAndDestroy(); // appArcIcon +} + +/** + * Unregisters the applications to be back converted from AppArc + * so that they can be registered again with the same Uid but with + * new opaque data (needed for old S60 Java). + * This function needs to called only if making back conversion after + * the user has canceled the installation of Java 2.0. + * If back conversion is done while uninstalling Java 2.0, all Java applications + * have been uninstalled and there are no Uids to be unregistered. + * + * Leaves with error code if AppArc cannot be connected or if + * unregistrations cannot be committed. + */ +void CBackConverter::UnregisterOldMidletData() +{ + // connect to AppArc + RApaLsSession apaSession; + + TInt err = apaSession.Connect(); + if (KErrNone != err) + { + // Fatal error, try to connect again. The midlets cannot be back converted + // using the same uids as earlier if the unregistration cannot be done. + TInt retryCount = 0; + do + { + ELOG1(EJavaConverters, + "CBackConverter::UnregisterCurrentJavaAppsL Cannot connect to " + "AppArc server, err %d", err); + + // wait + User::After(KDelayWhenWaitingAppArc); + + err = apaSession.Connect(); + if (KErrNone == err) + { + break; + } + + retryCount++; + } + while (retryCount < 10); + + if (KErrNone != err) + { + return; + } + } + + // Delete any pending (un)registrations (possible if + // e.g. device rebooted before commit). + // This call does nothing if there is no pending registrations. + // Ignore errors. + (void)apaSession.RollbackNonNativeApplicationsUpdates(); + + // Prepare for Java application unregistrations + TRAP(err, apaSession.PrepareNonNativeApplicationsUpdatesL()); + if (KErrNone != err) + { + ELOG1(EJavaConverters, + "CBackConverter::UnregisterCurrentJavaAppsL: " + "PrepareNonNativeApplicationsUpdatesL leaved with err %d", + err); + apaSession.Close(); + return; + } + + // Unregister all apps + CMidletInfo *midlet = iMidlets->GetFirst(); + + while (NULL != midlet) + { + TRAP(err, apaSession.DeregisterNonNativeApplicationL(midlet->GetMidletUid())); + if (KErrNone != err) + { + WLOG2(EJavaConverters, + "CBackConverter::UnregisterCurrentJavaAppsL: " + "DeregisterNonNativeApplicationL leaved with err %d for uid %d", + err, midlet->GetMidletUid().iUid); + // Ignore error, this particular application cannot be back converted. + } + + midlet = iMidlets->GetNext(); + } + + // Commit unregistrations + TRAP(err, apaSession.CommitNonNativeApplicationsUpdatesL()) + { + if (KErrNone != err) + { + ELOG1(EJavaConverters, + "CBackConverter::UnregisterCurrentJavaAppsL: " + "CommitNonNativeApplicationsUpdatesL leaved with err %d", + err); + apaSession.Close(); + return; + } + } + + apaSession.Close(); + return; +} + +/** + * Remove data file that contains info about midlets to be back converted. + */ +void CBackConverter::RemoveDataFile() +{ + TFileName dataFile(KMidletImportDirectory); + dataFile.Append(KMidletExportDataFileName); + + TInt err = iFs.Delete(dataFile); + if (KErrNone != err) + { + ELOG1(EJavaConverters, + "CBackConverter::RemoveDataFile: Cannot delete data file, err %d ", + err); + } +}