1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <e32debug.h> |
|
17 #include <savepriv.h> |
|
18 #include <s32mem.h> |
|
19 #include <ssm/ssmstatemanager.h> |
|
20 #include "lafshutdowneventobserveradaptor.h" |
|
21 |
|
22 _LIT( KLafShutDLL, "loadlafshutdown.dll" ); |
|
23 typedef MSsmLoadLafShut* (*TFuncLoadLafShutL)(void); |
|
24 |
|
25 const TInt KNumConnectRetries =10; |
|
26 //number of times re request the shutdown server for registered client array when |
|
27 //server side client array count is not equal to client side array count |
|
28 const TInt KMaxNumOfRetries = 2; |
|
29 |
|
30 const TUid KServerUid3={0x10004902}; |
|
31 _LIT(KShutdownSrvName,"shutdownsrvs"); |
|
32 |
|
33 /** |
|
34 Used to create an instance of CLafShutdownEventObserverAdaptor. |
|
35 |
|
36 @return A pointer to an object of type CLafShutdownEventObserverAdaptor. |
|
37 */ |
|
38 EXPORT_C MSsmUtility* CLafShutdownEventObserverAdaptor::NewL() |
|
39 { |
|
40 CLafShutdownEventObserverAdaptor* self = new (ELeave) CLafShutdownEventObserverAdaptor(); |
|
41 return static_cast<MSsmUtility*>(self); |
|
42 } |
|
43 |
|
44 /** |
|
45 Used to Initialize the utlity plugin. |
|
46 @see MSsmUtility::InitializeL() |
|
47 */ |
|
48 void CLafShutdownEventObserverAdaptor::InitializeL() |
|
49 { |
|
50 User::LeaveIfError(iLafShutLib.Load(KLafShutDLL)); |
|
51 TFuncLoadLafShutL lafShut = reinterpret_cast<TFuncLoadLafShutL>(iLafShutLib.Lookup(1)); |
|
52 iLafShutdown = lafShut(); |
|
53 User::LeaveIfNull(iLafShutdown); |
|
54 iLafShutdown->CreateShutdownManager(*this); |
|
55 } |
|
56 |
|
57 /** |
|
58 Starts the utility plugin. |
|
59 @see MSsmUtility::StartL() |
|
60 */ |
|
61 void CLafShutdownEventObserverAdaptor::StartL() |
|
62 { |
|
63 User::LeaveIfError(iShutdownSrvSession.ConnectL()); |
|
64 } |
|
65 |
|
66 /** |
|
67 Release memory associated with this SUP. |
|
68 @see MSsmUtility::Release() |
|
69 */ |
|
70 void CLafShutdownEventObserverAdaptor::Release() |
|
71 { |
|
72 iLafShutdown->DeleteShutdownManager(); |
|
73 iLafShutdown = NULL; |
|
74 iLafShutLib.Close(); |
|
75 } |
|
76 |
|
77 /** |
|
78 This function notifies all client registered for shutdown notification, and issues a state change to shutdown. |
|
79 @panic EInvalidSession If shutdown server's session is invalid |
|
80 */ |
|
81 void CLafShutdownEventObserverAdaptor::HandleShutdownEventL(MSaveObserver::TSaveType aAction, TBool aPowerOff, TPowerState aEvent) |
|
82 { |
|
83 __ASSERT_ALWAYS(iShutdownSrvSession.Handle(), User::Panic(KPanicShutdownEventObserverAdaptor, EInvalidSession)); |
|
84 //HandleShutdownEventL() will call NotifySave() |
|
85 iShutdownSrvSession.HandleShutdownEventL(aAction, aPowerOff, aEvent); |
|
86 |
|
87 //Connect to System State Manager |
|
88 //Create a shutdown state for transition |
|
89 //Request for shutdown transition passing the shutdown event |
|
90 RSsmStateManager stateManager; |
|
91 User::LeaveIfError(stateManager.Connect()); |
|
92 TSsmStateTransition state(ESsmShutdown, KSsmAnySubState, aEvent); |
|
93 stateManager.RequestStateTransition(state); |
|
94 stateManager.Close(); |
|
95 } |
|
96 |
|
97 /** |
|
98 @panic EInvalidSession If shutdown server's session is invalid |
|
99 */ |
|
100 CArrayFix<TThreadId>* CLafShutdownEventObserverAdaptor::ClientArrayLC() |
|
101 { |
|
102 __ASSERT_ALWAYS(iShutdownSrvSession.Handle(), User::Panic(KPanicShutdownEventObserverAdaptor, EInvalidSession)); |
|
103 return iShutdownSrvSession.ClientArrayLC(); |
|
104 } |
|
105 |
|
106 /** |
|
107 @panic EInvalidSession If shutdown server's session is invalid |
|
108 */ |
|
109 TBool CLafShutdownEventObserverAdaptor::IsClientHung(TThreadId aId) const |
|
110 { |
|
111 __ASSERT_ALWAYS(iShutdownSrvSession.Handle(), User::Panic(KPanicShutdownEventObserverAdaptor, EInvalidSession)); |
|
112 return iShutdownSrvSession.IsClientHung(aId); |
|
113 } |
|
114 |
|
115 /** |
|
116 @panic EInvalidSession If shutdown server's session is invalid |
|
117 */ |
|
118 void CLafShutdownEventObserverAdaptor::GetShutdownState(TBool& aPowerOff, TBool& aAllSessionsHavePendingRequest) const |
|
119 { |
|
120 __ASSERT_ALWAYS(iShutdownSrvSession.Handle(), User::Panic(KPanicShutdownEventObserverAdaptor, EInvalidSession)); |
|
121 iShutdownSrvSession.GetShutdownState(aPowerOff, aAllSessionsHavePendingRequest); |
|
122 } |
|
123 |
|
124 CLafShutdownEventObserverAdaptor::CLafShutdownEventObserverAdaptor() |
|
125 { |
|
126 } |
|
127 |
|
128 CLafShutdownEventObserverAdaptor::~CLafShutdownEventObserverAdaptor() |
|
129 { |
|
130 } |
|
131 |
|
132 /** |
|
133 This method will establish the connection with the shutdown server. If the shutdown server |
|
134 is not started yet, it will be started. |
|
135 @return KErrNone The connection was established successfully. |
|
136 @return Some other system-wide error codes |
|
137 */ |
|
138 TInt CLafShutdownEventObserverAdaptor::RShutdownSrvSession::ConnectL() |
|
139 { |
|
140 TInt err=KErrNone; |
|
141 TInt retry=KNumConnectRetries; |
|
142 FOREVER |
|
143 { |
|
144 err = CreateSession(__SHUTDOWN_SERVER_NAME, TVersion(KShutdownMajorVN,KShutdownMinorVN,KShutdownBuildVN), KShutdownMessageSlots); |
|
145 if ((--retry>0) && ((err==KErrNotFound) || (err==KErrServerTerminated))) |
|
146 { |
|
147 err = StartServerL(); |
|
148 if ((err!=KErrNone) && (err!=KErrAlreadyExists)) |
|
149 { |
|
150 break; |
|
151 } |
|
152 } |
|
153 else |
|
154 { |
|
155 break; |
|
156 } |
|
157 } |
|
158 return err; |
|
159 } |
|
160 |
|
161 /** |
|
162 This method starts the shutdown server. |
|
163 @return KErrNone The server was started successfully. |
|
164 @return KErrAlreadyExists The server is started already. |
|
165 @return Some other system-wide error codes |
|
166 */ |
|
167 TInt CLafShutdownEventObserverAdaptor::RShutdownSrvSession::StartServerL() |
|
168 { |
|
169 TInt error=KErrNone; |
|
170 const TUidType serverUid(KNullUid,KNullUid,KServerUid3); |
|
171 |
|
172 RProcess server; |
|
173 error = server.Create(KShutdownSrvName,KNullDesC,serverUid); |
|
174 if(error!=KErrNone) |
|
175 return error; |
|
176 TRequestStatus stat; |
|
177 server.Rendezvous(stat); |
|
178 if (stat!=KRequestPending) |
|
179 server.Kill(0); // abort startup |
|
180 else |
|
181 server.Resume(); // logon OK - start the server |
|
182 User::WaitForRequest(stat); // wait for start or death |
|
183 // we can't use the 'exit reason' if the server panicked as this |
|
184 // is the panic 'reason' and may be '0' which cannot be distinguished |
|
185 // from KErrNone |
|
186 error=(server.ExitType()==EExitPanic) ? KErrGeneral : stat.Int(); |
|
187 server.Close(); |
|
188 return error; |
|
189 } |
|
190 |
|
191 /** |
|
192 This method has to be called, when the registered clients have to be notified that a |
|
193 particular action has to be done, such as MSaveObserver::ESaveData, MSaveObserver::ESaveAll, |
|
194 MSaveObserver::EReleaseRAM,... |
|
195 If the requested action is not MSaveObserver::ESaveNone, the method will call |
|
196 CServShutdownServer::NotifySave(). |
|
197 @param aAction The type of the requested action |
|
198 @param aPowerOff If it is non-zero, this is the beginning of a powerdown sequence. |
|
199 @param aEvent The type of the powerdown event (power off or restart) |
|
200 @leave KErrNotSupported Leaves if aEvent is invalid |
|
201 @see CServShutdownServer::NotifySave() |
|
202 @see TPowerState |
|
203 */ |
|
204 void CLafShutdownEventObserverAdaptor::RShutdownSrvSession::HandleShutdownEventL(MSaveObserver::TSaveType aAction, TBool aPowerOff, TPowerState aEvent) |
|
205 { |
|
206 SendReceive(EEventObsAdaptHandleShutdown, TIpcArgs(aAction, aPowerOff, aEvent)); |
|
207 } |
|
208 |
|
209 /** |
|
210 This method creates an array of CArrayFix<TThreadId> type and appends to it the |
|
211 thread id-s of the all registered clients. |
|
212 The created CArrayFix<TThreadId> instance will be pushed on the cleanup stack. |
|
213 Logic for this function is as follows |
|
214 step1: Request the shutdown server to get the count of registered clients. |
|
215 step2: Create buffer of size arrayCount * sizeof(TThreadId). |
|
216 step3: Request the shutdown server to get the array of registered clients. If some client |
|
217 is registered after step 2 then server will return new count and empty buffer. |
|
218 step4: If buffer is emptey and server side client array is not equal to client side array |
|
219 count then repeat the step 3 for 2 times. |
|
220 step5: if client side array count is equal to server side client array count then append thread ids |
|
221 to array and return the array else return empty array. |
|
222 @return A pointer to a CArrayFix<TThreadId> array with the client thread id-s.if client side array count |
|
223 is equal to server side client array count then append thread ids to array and return the array else return empty array. |
|
224 */ |
|
225 CArrayFix<TThreadId>* CLafShutdownEventObserverAdaptor::RShutdownSrvSession::ClientArrayLC() |
|
226 { |
|
227 CArrayFix<TThreadId>* clientArray = new (ELeave) CArrayFixFlat<TThreadId>(2); |
|
228 CleanupStack::PushL(clientArray); |
|
229 |
|
230 //arrayCount refers to the array count at server side |
|
231 TInt arrayCount = 0; |
|
232 TPckg<TInt> pckg(arrayCount); |
|
233 User::LeaveIfError(SendReceive(EEventObsAdaptClientArrayCount, TIpcArgs(&pckg))); |
|
234 //return an empty array because arrayCount is 0 |
|
235 if (arrayCount > 0) |
|
236 { |
|
237 CBufFlat* buffer = CBufFlat::NewL(arrayCount * sizeof(TThreadId)); |
|
238 CleanupStack::PushL(buffer); |
|
239 |
|
240 TPtr8 bufPtr = buffer->Ptr(0); |
|
241 TInt clientSideArrayCount = 0; //clientSideArrayCount refers to the array count at client side |
|
242 //Request the server to get the registered clients. If server side array count is not equal to client |
|
243 //side array count then retry to request the server for KMaxNumOfRetries times |
|
244 for (TInt numOfRetries = 0; clientSideArrayCount != arrayCount && numOfRetries <= KMaxNumOfRetries; ++numOfRetries ) |
|
245 { |
|
246 clientSideArrayCount = arrayCount; |
|
247 buffer->ResizeL(clientSideArrayCount * sizeof(TThreadId)); |
|
248 bufPtr.Set(buffer->Ptr(0)); |
|
249 User::LeaveIfError(SendReceive(EEventObsAdaptClientArray, TIpcArgs(&bufPtr,clientSideArrayCount,&pckg))); |
|
250 } |
|
251 |
|
252 if (clientSideArrayCount != arrayCount) //retries exhausted and count doesn't match |
|
253 { |
|
254 CleanupStack::PopAndDestroy(buffer); |
|
255 User::Leave(KErrGeneral); |
|
256 } |
|
257 |
|
258 RBufReadStream readStream(*buffer); |
|
259 readStream.PushL(); |
|
260 TKeyArrayFix key(0,ECmpTInt); |
|
261 |
|
262 for (TInt i = 0; i < arrayCount; ++i) |
|
263 { |
|
264 const TInt32 threadHighBit = readStream.ReadUint32L(); |
|
265 const TInt32 threadLowBit = readStream.ReadUint32L(); |
|
266 TThreadId threadId(MAKE_TINT64(threadHighBit, threadLowBit)); |
|
267 TInt pos; |
|
268 if (0 != clientArray->Find(threadId,key,pos)) |
|
269 { |
|
270 clientArray->AppendL(threadId); |
|
271 } |
|
272 } |
|
273 readStream.Pop(); |
|
274 readStream.Close(); |
|
275 CleanupStack::PopAndDestroy(buffer); |
|
276 } |
|
277 return clientArray; |
|
278 } |
|
279 /** |
|
280 This method checks for pending request of a client's thread, which is passed through aId. |
|
281 @param aId Client's thread id. |
|
282 @return ETrue if the client with this thread id has no pending request otherwise EFalse. |
|
283 */ |
|
284 TBool CLafShutdownEventObserverAdaptor::RShutdownSrvSession::IsClientHung(TThreadId aId) const |
|
285 { |
|
286 TBool retVal = EFalse; |
|
287 TPckg<TInt32> pkg1(aId); |
|
288 TPckg<TInt32> pkg2(retVal); |
|
289 TIpcArgs args(&pkg1, &pkg2); |
|
290 |
|
291 SendReceive(EEventObsAdaptIsClientHung, args); |
|
292 |
|
293 return retVal; |
|
294 } |
|
295 |
|
296 /** |
|
297 This method returns an information about the shutdown status. |
|
298 @param aPowerOff An output parameter. It will be non-zero, if a powerdown sequence |
|
299 has been initiated. |
|
300 @param aAllSessionsHavePendingRequest It will be non-zero, if all clients has pending requests. |
|
301 */ |
|
302 void CLafShutdownEventObserverAdaptor::RShutdownSrvSession::GetShutdownState(TBool& aPowerOff, TBool& aAllSessionsHavePendingRequest) const |
|
303 { |
|
304 TPckg<TBool> powerOff(aPowerOff); |
|
305 TPckg<TBool> allSessionsHavePendingRequest(aAllSessionsHavePendingRequest); |
|
306 TIpcArgs args(&powerOff, &allSessionsHavePendingRequest); |
|
307 SendReceive(EEventObsAdaptGetShutdownState, args); |
|
308 } |
|
309 |
|