Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase.
Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.
// pubsub.cpp
//
// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//
#include <fshell/common.mmh>
#include <fshell/memoryaccesscmd.h>
#ifdef FSHELL_TRACE_SUPPORT
#include <fshell/extrabtrace.h>
#include <fshell/btrace_parser.h>
#endif
#include <fshell/ltkutils.h>
#include <fshell/qr3dll.h>
using namespace IoUtils;
#ifdef FSHELL_TRACE_SUPPORT
class CCmdPubsub : public CMemoryAccessCommandBase, public MBtracePubSubObserver
{
private: // From MBtracePubSubObserver
void HandlePropertyChangedL(const TBtraceTickCount& aTickCount, TUint aCategory, TUint aKey, TInt aNewValue);
void HandlePropertyChangedL(const TBtraceTickCount& aTickCount, TUint aCategory, TUint aKey, const TDesC8& aNewValue);
#else
class CCmdPubsub : public CMemoryAccessCommandBase
{
#endif
public:
static CCommandBase* NewLC();
~CCmdPubsub();
private:
CCmdPubsub();
void PrintKey(TUint aCategory, TUint aKey, TBool aFull=EFalse);
template <class KEYTYPE>
void SetKeyL(const KEYTYPE& aVal);
static TInt PropertyChanged(TAny* aSelf);
void GetAllL(TBool aNotify);
TBool IsExcluded(TUint aCat, TUint aKey) const;
private: // From CCommandBase.
virtual const TDesC& Name() const;
virtual void DoRunL();
virtual void ArgumentsL(RCommandArgumentList& aArguments);
virtual void OptionsL(RCommandOptionList& aOptions);
void DoCancel();
void RunL();
private:
// Arguments
enum TCmd
{
EGet, ESet, EDefine, ENotify
};
TCmd iCommand;
TUid iCategory;
TUint iKey;
// Options
HBufC* iStringVal;
TInt iIntVal;
TBool iForce;
TBool iNotify;
TBool iDefine;
// Other assorted stuff
#ifdef FSHELL_MEMORY_ACCESS_SUPPORT
TPropNotifyResult iNotifyResult;
#endif
#ifdef FSHELL_TRACE_SUPPORT
CBtraceReader* iReader;
CBtracePubSub* iPubSub;
#endif
TBool iUseBtrace;
CPropertyManager* iPropertyManager;
RBuf8 iValDescription;
};
CCommandBase* CCmdPubsub::NewLC()
{
CCmdPubsub* self = new(ELeave) CCmdPubsub();
CleanupStack::PushL(self);
self->BaseConstructL();
return self;
}
CCmdPubsub::~CCmdPubsub()
{
Cancel();
delete iStringVal;
#ifdef FSHELL_TRACE_SUPPORT
delete iPubSub;
delete iReader;
#endif
delete iPropertyManager;
iValDescription.Close();
}
CCmdPubsub::CCmdPubsub()
: CMemoryAccessCommandBase(EManualComplete)
{
}
const TDesC& CCmdPubsub::Name() const
{
_LIT(KName, "pubsub");
return KName;
}
void CCmdPubsub::DoRunL()
{
#if defined (FSHELL_MEMORY_ACCESS_SUPPORT)
if (iForce || iUseBtrace)
{
// In order to implement the --force option, we talk to the memaccess device driver, which uses an RPropertyRef
// that isn't subject to security checks
LoadMemoryAccessL();
}
#endif
iValDescription.CreateL(RProperty::KMaxLargePropertySize);
/*
if (iDelete)
{
if (!iArgList->IsPresent(1))
{
// Delete all not supported for pubsub
PrintError(KErrArgument, _L("You must specify a key for the delete option"));
User::Leave(KErrArgument);
}
else
{
#ifdef FSHELL_MEMORY_ACCESS_SUPPORT
if (iForce)
{
err = iMemAccess.DeleteProperty(iCategory, iKey);
}
else
#endif
{
err = RProperty::Delete(iCategory, iKey);
}
}
if (err == KErrPermissionDenied)
{
PrintError(err, _L("Delete failed, retry with --force"));
}
User::LeaveIfError(err);
}
*/
if (iCommand == EDefine) iDefine = ETrue;
if (iCommand == ENotify) iNotify = ETrue;
if ((iCommand == ESet) || iDefine)
{
if (iOptions.IsPresent(&iIntVal))
{
// Set int
SetKeyL(iIntVal);
}
else if (iOptions.IsPresent(&iStringVal))
{
// Set string
TPtrC8 data((TUint8*)iStringVal->Ptr(), iStringVal->Size());
SetKeyL(data);
}
else
{
LeaveIfErr(KErrArgument, _L("set/define command requires --int or --string arguments"));
}
}
else if ((iCommand == EGet) || iNotify)
{
// Get
if (!iArguments.IsPresent(1))
LeaveIfErr(KErrArgument, _L("get command requires key and category"));
PrintKey(iCategory.iUid, iKey, ETrue);
if (iNotify)
{
#if defined (FSHELL_MEMORY_ACCESS_SUPPORT)
if (iForce || iUseBtrace)
{
//TPckgBuf<SKeyPair> key;
//key().iCat = iCategory.iUid;
//key().iKey = iKey;
//LeaveIfErr(iMemAccess.SetupMassPropertyNotify(key), _L("Couldn't set up notification"));
LeaveIfErr(iMemAccess.SubscribeToProperty(iCategory, iKey, iUseBtrace), _L("Couldn't subscribe to property"));
#ifdef FSHELL_TRACE_SUPPORT
if (iUseBtrace)
{
const TInt KFlushInterval = 1000000; // 1s
const TInt KBtraceBufferSize = 1 * 1024 * 1024;
TRAPL(iReader = CBtraceReader::NewL(CBtraceReader::EFlushOnBtraceThreshold, KBtraceBufferSize, KBtraceBufferSize / 2), _L("Couldn't create btrace reader"));
TRAPL(iPubSub = CBtracePubSub::NewL(*iReader), _L("Couldn't create CBtracePubSub"));
TBtraceTickCount now;
now.SetToNow();
iReader->Start(now, KFlushInterval);
iPubSub->NotifyPropertyChangedL(*this);
return; // iPubSub will take it from here
}
else
#endif
{
iMemAccess.NotifyPropertyChange(iNotifyResult, iStatus);
SetActive();
}
}
else
#endif
{
iPropertyManager = CPropertyManager::NewL(TCallBack(&PropertyChanged, this));
iPropertyManager->ChangeProperty(iCategory.iUid, iKey);
}
return; // Don't complete
}
}
Complete();
}
template <class KEYTYPE>
void CCmdPubsub::SetKeyL(const KEYTYPE& aVal)
{
if (!iArguments.IsPresent(1))
{
LeaveIfErr(KErrArgument, _L("You must specify a key to set"));
}
TInt err = KErrNone;
#if defined (FSHELL_MEMORY_ACCESS_SUPPORT)
if (iForce)
{
err = iMemAccess.SetProperty(iCategory, iKey, aVal);
}
else
#endif
{
err = RProperty::Set(iCategory, iKey, aVal);
if (err == KErrArgument)
{
LeaveIfErr(err, _L("Key does not appear to be of the right type"));
}
}
#if defined (FSHELL_MEMORY_ACCESS_SUPPORT)
if (err == KErrNotFound && iDefine)
{
if (!iForce)
{
LeaveIfErr(err, _L("Key does not exist, cannot define it unless --force is also specified"));
}
err = iMemAccess.SetProperty(iCategory, iKey, aVal, ETrue);
}
#endif
if (err)
{
LeaveIfErr(err, _L("Error setting key"));
}
}
void CCmdPubsub::PrintKey(TUint aCategory, TUint aKey, TBool aFull)
{
TUid cat = { aCategory };
TInt valInt;
RBuf8& valDes = iValDescription;
valDes.Zero();
enum TType { EUnknown, EInt, EDes };
TType type = EUnknown;
TInt reallen = 0;
TInt err = KErrNotFound;
#if defined (FSHELL_MEMORY_ACCESS_SUPPORT)
if (iForce)
{
err = iMemAccess.GetProperty(cat, aKey, valInt);
if (err == KErrNone)
{
type = EInt;
}
else
{
err = iMemAccess.GetProperty(cat, aKey, valDes, reallen);
type = EDes;
}
}
else
#endif
{
// Guess the value type
// Int?
if (type == EUnknown)
{
err = RProperty::Get(cat, aKey, valInt);
if (err != KErrArgument)
{
type = EInt;
}
}
if (type == EUnknown)
{
// Des?
err = RProperty::Get(cat, aKey, valDes);
if (err != KErrArgument)
{
type = EDes;
}
}
}
switch(err)
{
case KErrNotFound:
PrintError(err, _L("Key 0x%x 0x%x not found"), aCategory, aKey);
break;
case KErrArgument:
PrintError(err, _L("Unknown key type, not int, des8 or des16"));
break;
case KErrPermissionDenied:
PrintError(err, _L("Permission denied on 0x%x 0x%x, retry with --force"), aCategory, aKey);
break;
case KErrNone:
// do nothing
break;
default:
PrintError(err, _L("Unrecognised error returned from RProperty"));
break;
}
if (err == KErrNone)
{
switch (type)
{
case EInt:
Printf(_L("0x%08x 0x%08x TInt: %d (0x%x)\r\n"), aCategory, aKey, valInt, valInt);
break;
case EDes:
{
TPtrC8 des(valDes);
if (!aFull) des.Set(valDes.Left(32)); // Don't print the whole thing, only 2 lines max
Printf(_L("0x%08x 0x%08x TDesC8 hex dump:\r\n"), aCategory, aKey);
LtkUtils::HexDumpToOutput(des, Stdout());
if (des.Length() < valDes.Length()) Write(_L("...\r\n"));
break;
}
default:
break;
}
}
}
void CCmdPubsub::ArgumentsL(RCommandArgumentList& aArguments)
{
aArguments.AppendEnumL((TInt&)iCommand, _L("command"));
aArguments.AppendUintL((TUint&)iCategory.iUid, _L("category"));
aArguments.AppendUintL(iKey, _L("key"));
}
void CCmdPubsub::OptionsL(RCommandOptionList& aOptions)
{
aOptions.AppendIntL(iIntVal, _L("int"));
aOptions.AppendStringL(iStringVal, _L("string"));
#ifdef FSHELL_MEMORY_ACCESS_SUPPORT
aOptions.AppendBoolL(iForce, _L("force"));
#endif
#ifdef FSHELL_TRACE_SUPPORT
aOptions.AppendBoolL(iUseBtrace, _L("btrace"));
#endif
//aOptions.AppendStringL(iStringVal, '8', _L("set-data"), _L("Sets the specified key to this 8-bit value"));
//aOptions.AppendBoolL(iDelete, 'l', _L("delete"), _L("Deletes the specified property"));
}
TInt CCmdPubsub::PropertyChanged(TAny* aSelf)
{
CCmdPubsub* self = static_cast<CCmdPubsub*>(aSelf);
self->PrintKey(self->iCategory.iUid, self->iKey);
return 0;
}
EXE_BOILER_PLATE(CCmdPubsub)
void CCmdPubsub::DoCancel()
{
#if defined (FSHELL_MEMORY_ACCESS_SUPPORT)
iMemAccess.CancelPropertyChange();
#endif
}
void CCmdPubsub::RunL()
{
#if defined (FSHELL_MEMORY_ACCESS_SUPPORT)
TPropNotifyResult notifyResult = iNotifyResult;
// rerequest asap
if (iStatus == KErrNone)
{
iMemAccess.NotifyPropertyChange(iNotifyResult, iStatus);
SetActive();
}
if (notifyResult.iMissedChanges)
{
PrintWarning(_L("Missed %d publish and subscribe notifications"), notifyResult.iMissedChanges);
}
if (notifyResult.iError)
{
Printf(_L("NotifyChange for 0x%08x 0x%x completed with error %d\r\n"), notifyResult.iCategory, notifyResult.iKey, notifyResult.iError);
}
else
{
//Printf(_L("P&S Key changed:\r\n"));
PrintKey(notifyResult.iCategory, notifyResult.iKey);
}
#endif
}
#ifdef FSHELL_TRACE_SUPPORT
void CCmdPubsub::HandlePropertyChangedL(const TBtraceTickCount&, TUint aCategory, TUint aKey, TInt /*aNewValue*/)
{
PrintKey(aCategory, aKey);
}
void CCmdPubsub::HandlePropertyChangedL(const TBtraceTickCount&, TUint aCategory, TUint aKey, const TDesC8& /*aNewValue*/)
{
PrintKey(aCategory, aKey);
}
#endif