--- /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 <e32base.h>
+#include <apgicnfl.h>
+#include <s32mem.h>
+#include <e32property.h>
+
+#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);
+ }
+}