--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qthighway/xqserviceutil/src/xqservicemanager.cpp Fri Apr 16 15:51:22 2010 +0300
@@ -0,0 +1,584 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, version 2.1 of the License.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this program. If not,
+* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
+*
+* Description:
+*
+*/
+
+#include "xqservicelog.h"
+#include <xqserviceglobal.h>
+
+#include "xqrequestutil.h"
+
+#include "xqservicemanager.h"
+#include "xqserviceipcconst.h"
+#include <QCoreApplication>
+#include <e32std.h>
+#include <w32std.h>
+
+#include <apparc.h>
+#include <apgcli.h>
+#include <apacln.h>
+#include <apgtask.h>
+#include <barsread2.h>
+#include <apacmdln.h>
+#include <coemain.h>
+
+#include <QBuffer>
+#include "xqservicemetadata/xqservicemetadata_p.h"
+#include <xqservicemetadata/xqaiwinterfacedescriptor.h>
+
+#include <QString>
+
+
+class XQServiceManagerPrivate
+ {
+ public:
+ XQServiceManagerPrivate() {iLatestError = 0;};
+ ~XQServiceManagerPrivate() {};
+
+ enum matchMode
+ {
+ MatchInterfaceName,
+ MatchServiceAndInterfaceName
+ };
+
+ int StartServer(const QString& aService, bool embedded, int& applicationUid, quint64& processId,
+ XQRequestUtil *util);
+ TInt Discover(const QString& aService,TUid& aAppUid, QList<XQAiwInterfaceDescriptor>& interfaces, int matchMode);
+ int LatestError() const {return iLatestError;};
+
+ private:
+ void StartServerL(const TUid& uid, bool embedded, TUint64& processId, XQRequestUtil *util);
+ TInt Discover(const TDesC& aService,TUid& aAppUid, QList<XQAiwInterfaceDescriptor>& interfaces, int matchMode);
+ CApaAppServiceInfoArray* AvailableServiceImplementationsL();
+ TUint64 getAppPid(const TUid& aAppUid);
+ int doMapErrors(TInt aError);
+
+ TVersion iVersion;
+ TApaAppInfo iAppInfo;
+ int iLatestError;
+ };
+
+XQServiceManager::XQServiceManager()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceManager::XQServiceManager");
+ d = new XQServiceManagerPrivate();
+}
+
+XQServiceManager::~XQServiceManager()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceManager::~XQServiceManager");
+ delete d;
+}
+
+/*!
+ Starts service
+ \param service The full name of service (servicename + interfacename)
+ \param embedded Start in embedded mode
+ \param applicationUid Returned applicatiion
+ \return List of implementations
+*/
+int XQServiceManager::startServer(const QString& service, bool embedded, int& applicationUid, quint64& threadId)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceManager::startServer(1)");
+ return startServer(service,embedded,applicationUid,threadId,NULL);
+}
+
+int XQServiceManager::startServer(const QString& service, bool embedded, int& applicationUid, quint64& threadId,
+ const void *userData)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceManager::startServer(2)");
+
+ // The "XQServiceRequest::send(QVariant& retData)" function passed the utility as user data
+ // the IPC layer. Could be NULL if no descriptor was given upon creating the request.
+ // The util data is known to be writeable (though passed as const userData)
+ XQRequestUtil *util = static_cast<XQRequestUtil*>((void *)userData);
+ if (util == 0)
+ {
+ // Something is badly wrong as this should be always avaible
+ return XQService::EMgrInternalError;
+ }
+
+ return d->StartServer(service,embedded,applicationUid,threadId, util);
+}
+
+
+/*!
+ Finds implementations for the given interface
+ \param interfaceName Interfacename to match
+ \return List of implementations
+*/
+QList<XQAiwInterfaceDescriptor> XQServiceManager::findInterfaces ( const QString &interfaceName ) const
+ {
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::findInterfaces");
+ QList<XQAiwInterfaceDescriptor> interfaces;
+ TUid appUid;
+ interfaces.clear();
+ TInt error=d->Discover(interfaceName, appUid, interfaces, XQServiceManagerPrivate::MatchInterfaceName);
+ return interfaces;
+ }
+
+/*!
+ Finds implementations for the given interface implemented by given service
+ \param serviceName Service name
+ \param interfaceName Interfacename to match
+ \return List of implementations
+*/
+QList<XQAiwInterfaceDescriptor> XQServiceManager::findInterfaces ( const QString &serviceName, const QString &interfaceName ) const
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::findInterfaces 2");
+ QList<XQAiwInterfaceDescriptor> interfaces;
+ TUid appUid;
+ interfaces.clear();
+ // Catenate to get full name
+ TInt error=d->Discover(serviceName + "." + interfaceName, appUid, interfaces,
+ XQServiceManagerPrivate::MatchServiceAndInterfaceName);
+ return interfaces;
+}
+
+
+/*!
+ Returns the latest error occured
+*/
+int XQServiceManager::latestError() const
+{
+ return d->LatestError();
+}
+
+// aService is here the full name (service + interface)
+int XQServiceManagerPrivate::StartServer(const QString& aService, bool embedded, int& applicationUid, quint64& processId,
+ XQRequestUtil *util)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::startServer(2)");
+ XQSERVICE_DEBUG_PRINT("aService: %s, embedded: %d", qPrintable(aService), embedded);
+
+ TUid appUid;
+ appUid.iUid=0;
+
+ TInt error = KErrNone;
+ QList<XQAiwInterfaceDescriptor> interfaces;
+ TPtrC serverName( reinterpret_cast<const TUint16*>(aService.utf16()) );
+ if (util->mDescriptor.isValid())
+ {
+ appUid.iUid = util->mDescriptor.property(XQAiwInterfaceDescriptor::ImplementationId).toInt();
+ XQSERVICE_DEBUG_PRINT("ApplicationUid from descriptor: %x", appUid.iUid);
+ }
+
+ // Need to discover service first if descriptor did not contained valid UID
+ // Otherwise, go directly starting the service server
+ if (appUid.iUid == 0)
+ {
+ error = Discover(serverName,appUid,interfaces, XQServiceManagerPrivate::MatchServiceAndInterfaceName);
+ }
+ if (error)
+ {
+ return doMapErrors(error);
+ }
+
+ TRAP(error, StartServerL(appUid,embedded,processId, util));
+ applicationUid = appUid.iUid ;
+
+ XQSERVICE_DEBUG_PRINT("ApplicationUid: %x, processId: %d", applicationUid, processId);
+ XQSERVICE_DEBUG_PRINT("error: %d", error);
+ return doMapErrors(error);
+}
+
+void XQServiceManagerPrivate::StartServerL(const TUid& uid, bool embedded, TUint64& processId,
+ XQRequestUtil *util)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::StartServerL");
+ Q_UNUSED(util); // Currently not used yet. The uid was set by calling function above
+
+ RApaLsSession apa;
+ User::LeaveIfError( apa.Connect() );
+ CleanupClosePushL( apa );
+
+
+ bool toBackground = false;
+ // Apply the utility's option for embedding
+ embedded = util->mInfo.isEmbedded();
+ toBackground = util->mInfo.isBackground();
+
+ XQSERVICE_DEBUG_PRINT("\tembedded got from utility=%d", embedded);
+ XQSERVICE_DEBUG_PRINT("\tbackground got from utility=%d", toBackground);
+
+ // retrieve application information
+ User::LeaveIfError( apa.GetAppInfo( iAppInfo, uid ) );
+
+ TApaAppCapabilityBuf caps;
+ User::LeaveIfError(apa.GetAppCapability(caps, uid));
+ if (!toBackground)
+ {
+ // If service wants to be launched to background.. respect it
+ toBackground = caps().iLaunchInBackground;
+ XQSERVICE_DEBUG_PRINT("\tbackground from apparch=%d", toBackground);
+ }
+
+ // Consistency check
+ if (embedded && toBackground)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ TFindServer find( iAppInfo.iCaption );
+ TFullName fullName;
+ TInt err = find.Next( fullName );
+ XQSERVICE_DEBUG_PRINT("err: %d", err);
+ if ( err != KErrNone )
+ {
+ CApaCommandLine* cmdLine = CApaCommandLine::NewLC();
+ cmdLine->SetExecutableNameL( iAppInfo.iFullName );
+ TApaCommand aLaunchCommand = toBackground ? EApaCommandBackground : EApaCommandRun;
+ cmdLine->SetCommandL(aLaunchCommand);
+
+ // just use the Secure ID as server differentiator
+ //cmdLine->SetServerRequiredL( uid.iUid );
+ RProcess client;
+ cmdLine->SetServerRequiredL(client.Id().Id());
+ if (embedded) {
+ CCoeEnv* env= CCoeEnv::Static();
+ if (env) // Could be NULL
+ {
+ RWindowGroup& wg = env->RootWin();
+ wg.AllowProcessToCreateChildWindowGroups(iAppInfo.iUid);
+ TInt parentId = wg.Identifier();
+ if (parentId)
+ {
+ // pass our window group ID to the embedded child process
+ cmdLine->SetParentWindowGroupID(parentId);
+ XQSERVICE_DEBUG_PRINT("\tParent ID %x set for %x (%x)", (int)parentId, iAppInfo.iUid, uid.iUid);
+ }
+ }
+ else
+ {
+ // Can not be embedded (non GUI client)
+ embedded = false;
+ util->mInfo.setEmbedded(false);
+ }
+ }
+
+ TRequestStatus requestStatusForRendezvous;
+
+ // start application with command line parameters
+ //User::LeaveIfError( apa.StartApp( *cmdLine, threadId, &requestStatusForRendezvous) );
+ QString startupArgs = QString::fromLatin1(XQServiceUtils::StartupArgService);
+ if (embedded)
+ {
+ startupArgs += (" " + QString::fromLatin1(XQServiceUtils::StartupArgEmbedded));
+ }
+ XQSERVICE_DEBUG_PRINT("\tStartupArgs:%s", qPrintable(startupArgs));
+ TPtrC cmdLineArgs( reinterpret_cast<const TUint16*>(startupArgs.utf16()) );
+
+ RProcess newApp;
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::Creating process");
+ User::LeaveIfError(newApp.Create(iAppInfo.iFullName, cmdLineArgs));
+ CleanupClosePushL(newApp);
+
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::Created process");
+ cmdLine->SetProcessEnvironmentL(newApp);
+ TProcessId newAppId = newApp.Id();
+ processId = newAppId.Id();
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::Rendezvous for %x", processId);
+ newApp.Rendezvous(requestStatusForRendezvous); // Asynchronous
+ newApp.Resume();
+
+ User::WaitForRequest( requestStatusForRendezvous ); // Make the rendezvouz
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::Rendezvous done %d", requestStatusForRendezvous.Int());
+
+ User::LeaveIfError( requestStatusForRendezvous.Int());
+ CleanupStack::PopAndDestroy(2,cmdLine); // newApp, cmdLine
+
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::Done");
+ }
+
+ CleanupStack::PopAndDestroy( &apa ); // ap
+}
+
+
+TUint64 XQServiceManagerPrivate::getAppPid(const TUid& aAppUid)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::getAppPid");
+ TUint64 pid = 0;
+ // Get the current task
+ RWsSession ws;
+ if (ws.Connect()==KErrNone) {
+ XQSERVICE_DEBUG_PRINT("Connected to window server");
+ TApaTaskList tasklist( ws );
+ TApaTask task = tasklist.FindApp( aAppUid );
+ if (task.Exists()) {
+ XQSERVICE_DEBUG_PRINT("Application found");
+ pid=task.ThreadId().Id();
+ }
+ }
+ return pid;
+}
+CApaAppServiceInfoArray* XQServiceManagerPrivate::AvailableServiceImplementationsL()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::AvailableServiceImplementationsL");
+ RApaLsSession ls;
+ User::LeaveIfError( ls.Connect() );
+ CleanupClosePushL( ls );
+ // retrieve list of available services implementations from apparc
+ CApaAppServiceInfoArray* apaInfo =
+ ls.GetServiceImplementationsLC(TUid::Uid(KXQServiceUid));
+ CleanupStack::Pop( apaInfo );
+ CleanupStack::PopAndDestroy( &ls );
+ return apaInfo;
+}
+
+TInt XQServiceManagerPrivate::Discover(const QString& aService,TUid& aAppUid, QList<XQAiwInterfaceDescriptor>& interfaces,
+ int matchMode)
+ {
+ TPtrC serverName( reinterpret_cast<const TUint16*>(aService.utf16()) );
+ TInt error=Discover(serverName, aAppUid, interfaces, matchMode);
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::Discover (1)");
+ return error;
+ }
+
+
+TInt XQServiceManagerPrivate::Discover( const TDesC& aService,
+ TUid& aAppUid, QList<XQAiwInterfaceDescriptor>& interfaces,
+ int matchMode)
+ {
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::Discover (2)");
+
+ CApaAppServiceInfoArray* apaInfo = NULL;
+ TInt error = KErrNone;
+ TRAP(error, apaInfo = AvailableServiceImplementationsL());
+ XQSERVICE_DEBUG_PRINT("error: %d", error);
+ if (error)
+ {
+ return error; // This is fatal as nothing found
+ }
+ TArray<TApaAppServiceInfo> implArray( apaInfo->Array() );
+ XQSERVICE_DEBUG_PRINT("implArray.Count(): %d", implArray.Count());
+ if ( !implArray.Count() )
+ {
+ delete apaInfo;
+ return KErrNotFound; // No services found
+ }
+
+ TBool found( EFalse );
+ QString serviceName = QString::fromUtf16(aService.Ptr(),aService.Length());
+ XQSERVICE_DEBUG_PRINT("serviceName: %s", qPrintable(serviceName));
+ for ( TInt ii = 0; ii < implArray.Count(); ii++ )
+ {
+
+ //
+ // Reset error for each check round
+ //
+ error = KErrNone;
+
+ TUid uid = implArray[ii].Uid();
+ XQSERVICE_DEBUG_PRINT("implArray[%d].UID=%x", ii, uid);
+
+ RResourceReader res;
+ // read opaque data
+ TRAP(error,res.OpenL( implArray[ii].OpaqueData() ) )
+ if ( error )
+ {
+ XQSERVICE_DEBUG_PRINT("OpaqueData error: %d", error);
+ delete apaInfo;
+ apaInfo = NULL;
+ continue; // Next could be OK
+ }
+
+ //the first WORD contains the number of elements in the resource
+ int count = 0;
+ TRAP(error,count = res.ReadInt16L());
+ if ( error )
+ {
+ XQSERVICE_DEBUG_PRINT("resource error1: %d", error);
+ res.Close();
+ delete apaInfo;
+ apaInfo = NULL;
+ continue; // Next could be OK
+ }
+ QByteArray xmlConf ;
+ XQSERVICE_DEBUG_PRINT("resource line count: %d", count);
+ for (int i=0; i < count ; i++)
+ {
+ TPtrC16 xmlBuf;
+ TRAP(error, xmlBuf.Set( res.ReadTPtrC16L() ));
+ if (error)
+ {
+ XQSERVICE_DEBUG_PRINT("resource error2: %d", error);
+ res.Close();
+ delete apaInfo;
+ apaInfo = NULL;
+ break;
+ }
+ else
+ {
+ QString str=QString::fromUtf16(xmlBuf.Ptr(),xmlBuf.Length());
+ XQSERVICE_DEBUG_PRINT("resource str: %s", qPrintable(str));
+ xmlConf.append(str.toAscii());
+ }
+ }
+
+ // If we stop loop for the first resource error,
+ // it will hit cases where same interface has been implemented by multiple services
+ // So go on checking all the resource files
+ if (error)
+ {
+ continue; // Next could be OK
+ }
+
+ XQSERVICE_DEBUG_PRINT("resource data: %s", xmlConf.constData());
+ QBuffer buf(&xmlConf);
+ ServiceMetaData* metaData = new ServiceMetaData(&buf);
+ if (metaData->extractMetadata())
+ {
+ ServiceMetaDataResults results=metaData->parseResults();
+ // interfaces = results.interfaces; // return value set here ???!!
+
+ // Go through all interfaces and pick the UI for the first matching one.
+ // THIS NEED TO BE FIXED IF SOMEONE WANTS DEDICATED IMPLEMENTATION
+ // Fill in the implementationId for all interfaces
+ TBool firstUidPicked(EFalse);
+ foreach (XQAiwInterfaceDescriptor interface,results.interfaces)
+ {
+ QString sn;
+ if (results.version == ServiceMetaDataResults::VERSION_1)
+ {
+ // Old version of the XML format. The parser took care of adaptation
+ // discovery-name = service-name + interface name
+ XQSERVICE_DEBUG_PRINT("version 1");
+ }
+ else
+ {
+ // discovery-name = interface name
+ XQSERVICE_DEBUG_PRINT("version 2");
+ }
+ // This is the name used in match
+ // TODO: Version handling support: Take the latest version if multiple matches
+ switch (matchMode)
+ {
+ case MatchInterfaceName :
+ sn = interface.interfaceName();
+ break;
+ case MatchServiceAndInterfaceName :
+ sn =interface.serviceName() + "." + interface.interfaceName();
+ break;
+ default:
+ sn = interface.interfaceName();
+ break;
+ }
+
+ XQSERVICE_DEBUG_PRINT("compare name is: %s", qPrintable(sn));
+ XQSERVICE_DEBUG_PRINT("requested name: %s", qPrintable(serviceName));
+ if (!serviceName.compare(sn,Qt::CaseInsensitive))
+ {
+ if (!firstUidPicked)
+ {
+ aAppUid = implArray[ii].Uid();
+ firstUidPicked = ETrue;
+ }
+ XQSERVICE_DEBUG_PRINT("Service found %x", aAppUid);
+ // Add impl. UID to interface
+ interface.setProperty(XQAiwInterfaceDescriptor::ImplementationId, (int)aAppUid.iUid);
+ found = ETrue;
+
+ // Add the matched interface to result set
+ interfaces.append(interface);
+
+ }
+ } // forearch interface
+ }
+ else
+ {
+ error = metaData->getLatestError();
+ XQSERVICE_DEBUG_PRINT("metadata error: %d", error);
+ }
+
+ delete metaData;
+ metaData = NULL;
+ res.Close();
+
+ } // for implArray ...
+
+ delete apaInfo;
+ if (!found)
+ {
+ error = KErrNotFound;
+ }
+
+ XQSERVICE_DEBUG_PRINT("Discover error: %d", error);
+
+ return error;
+}
+
+int XQServiceManagerPrivate::doMapErrors(TInt aError)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceManagerPrivate::doMapErrors");
+ XQSERVICE_DEBUG_PRINT("aError: %d", aError);
+ int error(XQService::ENoError);
+
+ switch (aError)
+ {
+ case KErrNone: {
+ error = XQService::ENoError;
+ break;
+ }
+ case KErrPermissionDenied:
+ case KErrServerTerminated: {
+ error = XQService::EConnectionClosed;
+ break;
+ }
+ case KErrServerBusy: {
+ error = XQService::EConnectionError;
+ break;
+ }
+ case KErrArgument:
+ {
+ error = XQService::EArgumentError;
+ break;
+ }
+
+ case KErrNoMemory: {
+ error = XQService::EIPCError;
+ break;
+ }
+ case KErrNotFound: {
+ error = XQService::EServerNotFound;
+ break;
+ }
+
+ default:
+ {
+
+ if (aError >= XQService::EMetaNoService && aError <= XQService::EMetaDuplicatedCustomKey)
+ {
+ iLatestError = error;
+ return error; // Already real error
+ }
+
+ error = XQService::EUnknownError;
+ break;
+ }
+ }
+
+ // Save error
+ iLatestError = error;
+
+ XQSERVICE_DEBUG_PRINT("error: %d", error);
+ return error;
+}
+
+
+