diff -r 000000000000 -r 7f656887cf89 libraries/memoryaccess/PropertyAccess.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libraries/memoryaccess/PropertyAccess.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,277 @@ +// PropertyAccess.cpp +// +// Copyright (c) 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 +#include +#include + +#include +#include +#include "memoryaccess.h" +#include "PropertyAccess.h" + +DPropertyAccess::DPropertyAccess(DThread* aClient) + : iClient(aClient) + { + } + +TInt DPropertyAccess::HandleProperty(TInt aFunction, TAny* aParams, TAny* aVal) + { + return DoHandleProperty(iClient, aFunction, aParams, aVal); + } + +TInt DPropertyAccess::DoHandleProperty(DThread* aClient, TInt aFunction, TAny* aParams, TAny* aVal) + { + if (aFunction == RMemoryAccess::EControlPropertyNotify) + { + if (iNotifyClientStatus) return KErrAlreadyExists; + iNotifyClientStatus = (TRequestStatus*)aVal; + iClientNotifyPtr = aParams; + return KErrNone; + } + else if (aFunction == RMemoryAccess::EControlPropertyNotifyCancel) + { + CancelNotifys(); + return KErrNone; + } + + TInt err; + TProp clientParams; + err = Kern::ThreadRawRead(aClient, aParams, &clientParams, sizeof(TProp)); + if (err) + { + return err; + } + //Kern::Printf("HandleProperty %d, iDefine=%d iCat=0x%x iKey=%d", aFunction, clientParams.iDefine, clientParams.iCategory, clientParams.iKey); + + NKern::ThreadEnterCS(); + RPropertyRef property; + err = property.Open(clientParams.iCategory, clientParams.iKey); + //Kern::Printf("HandleProperty Open ret=%d", err); + if (!err) + { + // Check if it exists but isn't defined (and if it isn't, treat it the same as if it didn't exist) + TPropertyStatus stat; + NKern::LockSystem(); + TBool defined = property.GetStatus(stat); + NKern::UnlockSystem(); + if (!defined) + { + property.Close(); + err = KErrNotFound; + } + } + + if (err == KErrNotFound && clientParams.iDefine && (aFunction == RMemoryAccess::EControlSetPropertyDesc || aFunction == RMemoryAccess::EControlSetPropertyInt)) + { + err = property.Attach(clientParams.iCategory, clientParams.iKey); + TInt attr = (aFunction == RMemoryAccess::EControlSetPropertyInt) ? RProperty::EInt : RProperty::EByteArray; + _LIT_SECURITY_POLICY_PASS(KPass); + if (!err) err = property.Define(attr, KPass, KPass); + } + NKern::ThreadLeaveCS(); + if (err) + { + return err; + } + + switch (aFunction) + { + case RMemoryAccess::EControlGetPropertyInt: + { + TInt val; + err = property.Get(val); + if (!err) + { + TPckg valBuf(val); + err = Kern::ThreadDesWrite(aClient, aVal, valBuf, 0); + } + break; + } + case RMemoryAccess::EControlGetPropertyDesc: + { + err = Kern::ThreadGetDesMaxLength(aClient, aVal); + TInt size = err; + if (size < 0) break; + + NKern::ThreadEnterCS(); + HBuf8* buf = HBuf8::New(size); + if (!buf) + { + err = KErrNoMemory; + NKern::ThreadLeaveCS(); + break; + } + err = property.Get(*buf); + if (!err || err == KErrOverflow) + { + TInt writeerr = Kern::ThreadDesWrite(aClient, aVal, *buf, 0, NULL); + if (writeerr) err = writeerr; + } + delete buf; + NKern::ThreadLeaveCS(); + if (err == KErrOverflow) + { + NKern::LockSystem(); + TPropertyStatus status; + property.GetStatus(status); + NKern::UnlockSystem(); + + clientParams.iActualSize = status.iSize; + err = Kern::ThreadRawWrite(aClient, aParams, (TAny*)&clientParams, sizeof(TProp)); + } + break; + } + case RMemoryAccess::EControlSetPropertyInt: + { + err = property.Set((TInt)aVal); + break; + } + case RMemoryAccess::EControlSetPropertyDesc: + { + err = Kern::ThreadGetDesLength(aClient, aVal); + TInt size = err; + if (size < 0) break; + + NKern::ThreadEnterCS(); + HBuf8* buf = HBuf8::New(size); + if (!buf) + { + err = KErrNoMemory; + NKern::ThreadLeaveCS(); + break; + } + buf->SetLength(size); + err = Kern::ThreadDesRead(aClient, aVal, *buf, 0); + if (!err) + { + err = property.Set(*buf); + } + delete buf; + NKern::ThreadLeaveCS(); + break; + } + case RMemoryAccess::EControlDeleteProperty: + NKern::ThreadEnterCS(); + err = property.Delete(); + NKern::ThreadLeaveCS(); + break; + case RMemoryAccess::EControlSubscribeToProperty: + { + TBool useBtrace = (TBool)aVal; + TNotifyRequest* req = new TNotifyRequest(&PropertyChanged, clientParams.iCategory, clientParams.iKey, this, useBtrace); + err = req->iProperty.Attach(clientParams.iCategory, clientParams.iKey); // Allow non-existant properties + if (!err) + { + err = req->iProperty.Subscribe(req->iRequest); + if (err) + { + // Don't think this will ever happen + req->iProperty.Close(); + req->iRequest.iPtr = NULL; + } + } + if (err) + { + delete req; + } + else + { + iRequests.Add(&req->iLink); + } + } + break; + default: + break; + } + + NKern::ThreadEnterCS(); + property.Close(); + NKern::ThreadLeaveCS(); + return err; + } + +DPropertyAccess::~DPropertyAccess() + { + CancelNotifys(); + } + +void DPropertyAccess::CancelNotifys() + { + for (SDblQueLink* link = iRequests.First(); link != NULL && link != &iRequests.iA;) + { + TNotifyRequest* request = _LOFF(link, TNotifyRequest, iLink); + link=link->iNext; // Do this before anything else because we'll be deleting the TNotifyRequest + request->iProperty.Cancel(request->iRequest); + request->iProperty.Close(); + delete request; + } + + if (iNotifyClientStatus) + { + Kern::RequestComplete(iClient, iNotifyClientStatus, KErrCancel); + } + iClientNotifyPtr = NULL; + } + +void DPropertyAccess::PropertyChanged(TAny* aPtr, TInt aReason) + { + TNotifyRequest* req = static_cast(aPtr); + req->iPropertyAccess->DoPropertyChanged(*req, aReason); + } + +void DPropertyAccess::DoPropertyChanged(TNotifyRequest& aRequest, TInt aReason) + { + // First, rerequest + if (aReason == KErrNone) + { + aRequest.iProperty.Subscribe(aRequest.iRequest); + } + // Then try and notify + if (iNotifyClientStatus && !aRequest.iBtrace) + { + TPropNotifyResult result; + result.iCategory = aRequest.iCat.iUid; + result.iKey = aRequest.iKey; + result.iMissedChanges = iMissedChanges; + result.iError = aReason; + iMissedChanges = 0; // No need to lock/safeswap because we run in the context of the pubsub DFC + TInt err = Kern::ThreadRawWrite(iClient, iClientNotifyPtr, &result, sizeof(TPropNotifyResult)); + Kern::RequestComplete(iClient, iNotifyClientStatus, err); + } + else if (aRequest.iBtrace) + { +#ifdef FSHELL_TRACE_SUPPORT + TUint cat = aRequest.iCat.iUid; + TUint key = aRequest.iKey; + + TInt intVal; + TInt err = aRequest.iProperty.Get(intVal); + if (err == KErrNone) + { + BTrace12(ExtraBTrace::EPubSub, ExtraBTrace::EPubSubIntPropertyChanged, cat, key, intVal); + } + else if (err == KErrArgument) + { + TBuf8 buf; // No point using larger buffer, as this is the max we can output over btrace (80 bytes) + err = aRequest.iProperty.Get(buf); + if (err == KErrNone || err == KErrOverflow) + { + BTraceN(ExtraBTrace::EPubSub, ExtraBTrace::EPubSubDataPropertyChanged, cat, key, buf.Ptr(), buf.Length()); + } + } +#endif + } + else + { + iMissedChanges++; + } + }