13
|
1 |
/*
|
|
2 |
* Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
3 |
* All rights reserved.
|
|
4 |
* This component and the accompanying materials are made available
|
|
5 |
* under the terms of the License "Eclipse Public License v1.0"
|
|
6 |
* which accompanies this distribution, and is available
|
|
7 |
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
|
8 |
*
|
|
9 |
* Initial Contributors:
|
|
10 |
* Nokia Corporation - initial contribution.
|
|
11 |
*
|
|
12 |
* Contributors:
|
|
13 |
*
|
|
14 |
* Description:
|
|
15 |
*
|
|
16 |
*/
|
|
17 |
|
|
18 |
|
|
19 |
#include "shutdownsrv.h"
|
|
20 |
#include "savenotf.h"
|
|
21 |
#include "savepriv.h"
|
|
22 |
#include "shutdowntimer.h"
|
|
23 |
#include <hal.h>
|
|
24 |
#include <f32file.h>
|
|
25 |
#include <bautils.h>
|
|
26 |
|
|
27 |
#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
|
|
28 |
#include <s32mem.h>
|
|
29 |
#include <ssmgracefulshutdown_patch.h>
|
|
30 |
#endif
|
|
31 |
|
|
32 |
//The function used to start the profiler, while profiling the shutdown.
|
|
33 |
#ifdef __PROFILE_SHUTDOWN
|
|
34 |
_LIT(KProfilerCmd,"start -noui");
|
|
35 |
void StartProfiler()
|
|
36 |
{
|
|
37 |
RProcess p;
|
|
38 |
TInt r=p.Create(KProfilerName,KProfilerCmd);
|
|
39 |
if (r==KErrNone)
|
|
40 |
{
|
|
41 |
p.Resume();
|
|
42 |
p.Close();
|
|
43 |
}
|
|
44 |
}
|
|
45 |
#endif
|
|
46 |
|
|
47 |
//The function used to unload the profiler, while profiling the shutdown.
|
|
48 |
#ifdef __PROFILE_SHUTDOWN
|
|
49 |
void UnloadProfiler()
|
|
50 |
{
|
|
51 |
TFullName name;
|
|
52 |
TFindServer findSvr(KProfilerName);
|
|
53 |
Profiler::Unload();
|
|
54 |
while(findSvr.Next(name) == KErrNone)
|
|
55 |
{
|
|
56 |
User::After(1000000);
|
|
57 |
findSvr.Find(KProfilerName);
|
|
58 |
}
|
|
59 |
}
|
|
60 |
#endif
|
|
61 |
|
|
62 |
//
|
|
63 |
// class CServShutdownServer
|
|
64 |
//
|
|
65 |
|
|
66 |
/**
|
|
67 |
Standard phase-one factory method for creating CServShutdownServer instances.
|
|
68 |
@return A newly-constructed shutdown server object.
|
|
69 |
@leave Some system-wide error codes including KErrNoMemory.
|
|
70 |
*/
|
|
71 |
EXPORT_C CServShutdownServer* CServShutdownServer::NewL()
|
|
72 |
{ // static
|
|
73 |
CServShutdownServer* self=new(ELeave) CServShutdownServer(CActive::EPriorityStandard);
|
|
74 |
return self;
|
|
75 |
}
|
|
76 |
|
|
77 |
/**
|
|
78 |
Destructor.
|
|
79 |
Releases CShutdownTimer object if it has been allocated.
|
|
80 |
*/
|
|
81 |
EXPORT_C CServShutdownServer::~CServShutdownServer()
|
|
82 |
{
|
|
83 |
delete iShutdownTimer;
|
|
84 |
}
|
|
85 |
|
|
86 |
/**
|
|
87 |
This method iterates through all session instances and checks that all they have pending
|
|
88 |
requests (which means that all clients have completed their powerdown related processing
|
|
89 |
and re-registered itself back to the shutdown server).. If that's true (all sessions have
|
|
90 |
pending requests) and iPowerOff flag is nonzero, the method will call SwitchOff() - the
|
|
91 |
power will be switched off.
|
|
92 |
@see CServShutdownServer::SwitchOff()
|
|
93 |
@see CServShutdownSession::HasPendingRequest()
|
|
94 |
*/
|
|
95 |
EXPORT_C void CServShutdownServer::HandlePowerNotifRequest(const RThread& /*aClient*/)
|
|
96 |
{
|
|
97 |
// if all sessions have a pending request then they've all saved their data and we can switch off
|
|
98 |
TBool completed=ETrue;
|
|
99 |
TDblQueIter<CSession2> iter(iSessionIter);
|
|
100 |
iter.SetToFirst();
|
|
101 |
|
|
102 |
for (CSession2* session=iter++; session!=NULL; session=iter++)
|
|
103 |
{
|
|
104 |
if (!static_cast<CServShutdownSession*>(session)->HasPendingRequest())
|
|
105 |
{
|
|
106 |
completed=EFalse;
|
|
107 |
break;
|
|
108 |
}
|
|
109 |
}
|
|
110 |
if (completed && iPowerOff)
|
|
111 |
{
|
|
112 |
SwitchOff();
|
|
113 |
}
|
|
114 |
}
|
|
115 |
|
|
116 |
/**
|
|
117 |
This method will call SwitchOff(), if there are no sessions, so - no clients.
|
|
118 |
If there are registered clients (sessions), the method will call CServShutdownSession::NotifySave()
|
|
119 |
for each of them.
|
|
120 |
If the timer object has been initialised, it calculates the shutdown timeout value
|
|
121 |
and adds the timer to the active scheduler.
|
|
122 |
@param aSaveType The action, which will be given to the clients, when calling their
|
|
123 |
MSaveObserver::SaveL() implementations.
|
|
124 |
@see CServShutdownServer::SwitchOff()
|
|
125 |
@see CServShutdownSession::NotifySave()
|
|
126 |
*/
|
|
127 |
EXPORT_C void CServShutdownServer::NotifySave(MSaveObserver::TSaveType aSaveType)
|
|
128 |
{
|
|
129 |
TDblQueIter<CSession2> iter(iSessionIter);
|
|
130 |
iter.SetToFirst();
|
|
131 |
CSession2* p=iter++;
|
|
132 |
if (p==NULL)
|
|
133 |
{
|
|
134 |
if (iPowerOff)
|
|
135 |
{
|
|
136 |
SwitchOff();
|
|
137 |
}
|
|
138 |
}
|
|
139 |
else
|
|
140 |
{
|
|
141 |
TInt numClients = 0;
|
|
142 |
|
|
143 |
iter.SetToFirst();
|
|
144 |
for (CSession2* session=iter++; session!=NULL; session=iter++)
|
|
145 |
{
|
|
146 |
static_cast<CServShutdownSession*>(session)->NotifySave(aSaveType);
|
|
147 |
numClients++;
|
|
148 |
}
|
|
149 |
|
|
150 |
if(iShutdownTimer && !iShutdownTimer->IsActive())
|
|
151 |
{
|
|
152 |
iShutdownTimer->Start(numClients);
|
|
153 |
}
|
|
154 |
}
|
|
155 |
}
|
|
156 |
|
|
157 |
/**
|
|
158 |
@return Non-zero If the powerdown sequence has been initiated.
|
|
159 |
*/
|
|
160 |
EXPORT_C TBool CServShutdownServer::IsPowerOff() const
|
|
161 |
{
|
|
162 |
return iPowerOff;
|
|
163 |
}
|
|
164 |
|
|
165 |
/**
|
|
166 |
Cancels any power off request.
|
|
167 |
*/
|
|
168 |
EXPORT_C void CServShutdownServer::CancelPowerOff()
|
|
169 |
{
|
|
170 |
iPowerOff=EFalse;
|
|
171 |
|
|
172 |
// Cancel the timer.
|
|
173 |
if (iShutdownTimer)
|
|
174 |
{
|
|
175 |
iShutdownTimer->Cancel();
|
|
176 |
}
|
|
177 |
}
|
|
178 |
|
|
179 |
/**
|
|
180 |
@param aPriority The active object priority.
|
|
181 |
*/
|
|
182 |
EXPORT_C CServShutdownServer::CServShutdownServer(TInt aPriority):
|
|
183 |
CServer2(aPriority), iShutdownTimer(0)
|
|
184 |
{
|
|
185 |
}
|
|
186 |
|
|
187 |
/**
|
|
188 |
Completes the server construction by adding the server to the active scheduler and initializing the
|
|
189 |
CShutdownTimer object if applicable.
|
|
190 |
@leave See CServer2::StartL() leave error codes.
|
|
191 |
@see CServer2::StartL()
|
|
192 |
@panic KErrNotSupported Incorrect patchable variables configuration.
|
|
193 |
*/
|
|
194 |
EXPORT_C void CServShutdownServer::ConstructL()
|
|
195 |
{
|
|
196 |
iShutdownTimer = CShutdownTimer::NewL(*this);
|
|
197 |
#ifdef TEST_SHUTDOWN_SERVER
|
|
198 |
StartL(__TEST_SHUTDOWN_SERVER_NAME);
|
|
199 |
#else
|
|
200 |
StartL(__SHUTDOWN_SERVER_NAME);
|
|
201 |
#endif
|
|
202 |
}
|
|
203 |
|
|
204 |
/**
|
|
205 |
This method switches off the power using the Power API.
|
|
206 |
If there is a defined SYSLIBS_TEST macro, the method does nothing.
|
|
207 |
*/
|
|
208 |
void CServShutdownServer::DoSwitchOff()
|
|
209 |
{
|
|
210 |
//Finalize the drives before shutting down
|
|
211 |
RFs fs;
|
|
212 |
TInt r=fs.Connect();
|
|
213 |
if (r==KErrNone)
|
|
214 |
{
|
|
215 |
//Ignore the error code, as it is not a critical call
|
|
216 |
r=fs.FinaliseDrives();
|
|
217 |
fs.Close();
|
|
218 |
}
|
|
219 |
#ifdef SYSLIBS_TEST
|
|
220 |
// Test mode, only prints debug message.
|
|
221 |
RDebug::Printf("CServShutdownServer::SwitchOff() gets run in SYSLIBS_TEST mode.\n");
|
|
222 |
#else //SYSLIBS_TEST
|
|
223 |
// restart or standby/shutdown using Power API
|
|
224 |
if (Power::EnableWakeupEvents(iPowerEvent) == KErrNone)
|
|
225 |
{
|
|
226 |
// Prepare to wake up if power event is standby
|
|
227 |
TRequestStatus s;
|
|
228 |
Power::RequestWakeupEventNotification(s);
|
|
229 |
Power::PowerDown(); // if event is Restart, this function should never return
|
|
230 |
User::WaitForRequest(s);
|
|
231 |
}
|
|
232 |
#endif //SYSLIBS_TEST
|
|
233 |
}
|
|
234 |
void CServShutdownServer::SwitchOff()
|
|
235 |
{
|
|
236 |
// If the timer has applied, cancel any outstanding requests,
|
|
237 |
// no matter SwitchOff() has been triggered by the timer or the shutdown server.
|
|
238 |
if (iShutdownTimer)
|
|
239 |
{
|
|
240 |
iShutdownTimer->Cancel();
|
|
241 |
}
|
|
242 |
|
|
243 |
if (iPowerOff)
|
|
244 |
{
|
|
245 |
#ifdef __PROFILE_SHUTDOWN
|
|
246 |
UnloadProfiler();
|
|
247 |
#endif //__PROFILE_SHUTDOWN
|
|
248 |
}
|
|
249 |
//SSM shutdown is used only when patchable constant KSsmGracefulShutdown is true
|
|
250 |
#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
|
|
251 |
if (iPowerOff && !IsSsmGracefulShutdown())
|
|
252 |
#else
|
|
253 |
if (iPowerOff)
|
|
254 |
#endif
|
|
255 |
{
|
|
256 |
//Shutdown using old shutdownsrv, not SSM
|
|
257 |
DoSwitchOff();
|
|
258 |
}
|
|
259 |
iPowerOff = EFalse;
|
|
260 |
}
|
|
261 |
|
|
262 |
/**
|
|
263 |
This method creates a new server side session object.
|
|
264 |
@param aVersion Shutdown server version number.
|
|
265 |
@return A pointer to the created session object.
|
|
266 |
@leave KErrNotSupported Unknown shutdown server version
|
|
267 |
@leave Some system-wide error codes including KErrNoMemory.
|
|
268 |
*/
|
|
269 |
CSession2* CServShutdownServer::NewSessionL(const TVersion& aVersion,const RMessage2& /*aMessage*/) const
|
|
270 |
{
|
|
271 |
TVersion v(KShutdownMajorVN,KShutdownMinorVN,KShutdownBuildVN);
|
|
272 |
if (!User::QueryVersionSupported(v,aVersion))
|
|
273 |
User::Leave(KErrNotSupported);
|
|
274 |
|
|
275 |
CSession2* pSession = CServShutdownSession::NewL();
|
|
276 |
return pSession;
|
|
277 |
}
|
|
278 |
|
|
279 |
/**
|
|
280 |
This method has to be called, when the registered clients have to be notified that a
|
|
281 |
particular action has to be done, such as MSaveObserver::ESaveData, MSaveObserver::ESaveAll,
|
|
282 |
MSaveObserver::EReleaseRAM,...
|
|
283 |
If this is a beginning of a powerdown sequence, the method will store the locales and the HAL
|
|
284 |
properties.
|
|
285 |
If the requested action is not MSaveObserver::ESaveNone, the method will call
|
|
286 |
CServShutdownServer::NotifySave().
|
|
287 |
@param aAction The type of the requested action
|
|
288 |
@param aPowerOff If it is non-zero, this is the beginning of a powerdown sequence.
|
|
289 |
@param aEvent The type of the powerdown event (power off or restart)
|
|
290 |
@leave KErrNotSupported Leaves if aEvent is invalid
|
|
291 |
@see CServShutdownServer::NotifySave()
|
|
292 |
@see TPowerState
|
|
293 |
*/
|
|
294 |
EXPORT_C void CServShutdownServer::HandleShutdownEventL(MSaveObserver::TSaveType aAction,TBool aPowerOff, TPowerState aEvent)
|
|
295 |
{
|
|
296 |
if( aPowerOff )
|
|
297 |
{
|
|
298 |
__ASSERT_ALWAYS((aEvent>EPwActive)&&(aEvent<EPwLimit), User::Leave(KErrNotSupported));
|
|
299 |
#ifdef __PROFILE_SHUTDOWN
|
|
300 |
StartProfiler();
|
|
301 |
#endif
|
|
302 |
|
|
303 |
#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
|
|
304 |
if (!IsSsmGracefulShutdown())
|
|
305 |
{
|
|
306 |
// Save the state of the HAL
|
|
307 |
// The state of the locale should be saved before the HAL
|
|
308 |
BaflUtils::PersistLocale();
|
|
309 |
BaflUtils::PersistHAL();
|
|
310 |
}
|
|
311 |
#else
|
|
312 |
// Save the state of the HAL
|
|
313 |
// The state of the locale should be saved before the HAL
|
|
314 |
BaflUtils::PersistLocale();
|
|
315 |
BaflUtils::PersistHAL();
|
|
316 |
#endif
|
|
317 |
}
|
|
318 |
|
|
319 |
iPowerOff=aPowerOff;
|
|
320 |
iPowerEvent = aEvent;
|
|
321 |
// add LAF setting for powering down screen (& keyboard??)
|
|
322 |
if (aAction != MSaveObserver::ESaveNone)
|
|
323 |
{
|
|
324 |
NotifySave(aAction);
|
|
325 |
}
|
|
326 |
}
|
|
327 |
|
|
328 |
/**
|
|
329 |
This method returns an information about the shutdown status.
|
|
330 |
@param aPowerOff An output parameter, where iPowerOff value will be stored.
|
|
331 |
It will be non-zero, if a powerdown sequence has been initiated.
|
|
332 |
@param aAllSessionsHavePendingRequest An output parameter. It will be non-zero, if
|
|
333 |
all clients has pending requests.
|
|
334 |
*/
|
|
335 |
EXPORT_C void CServShutdownServer::GetShutdownState(TBool& aPowerOff, TBool& aAllSessionsHavePendingRequest) const
|
|
336 |
{
|
|
337 |
aAllSessionsHavePendingRequest = AllSessionsHavePendingRequest();
|
|
338 |
aPowerOff = iPowerOff;
|
|
339 |
}
|
|
340 |
|
|
341 |
/**
|
|
342 |
This method creates an array of CArrayFix<TThreadId> type and appends to it the
|
|
343 |
thread id-s of the all registered clients.
|
|
344 |
The created CArrayFix<TThreadId> instance will be pushed on the cleanup stack.
|
|
345 |
@return A pointer to a CArrayFix<TThreadId> array with the client thread id-s.
|
|
346 |
@leave Some system-wide error codes including KErrNoMemory.
|
|
347 |
*/
|
|
348 |
EXPORT_C CArrayFix<TThreadId>* CServShutdownServer::ClientArrayLC()
|
|
349 |
{
|
|
350 |
CArrayFix<TThreadId>* clientArray=new(ELeave) CArrayFixFlat<TThreadId>(2);
|
|
351 |
CleanupStack::PushL(clientArray);
|
|
352 |
TDblQueIter<CSession2> iter(iSessionIter);
|
|
353 |
iter.SetToFirst();
|
|
354 |
TKeyArrayFix key(0,ECmpTInt);
|
|
355 |
for (CSession2* session=iter++; session!=NULL; session=iter++)
|
|
356 |
{
|
|
357 |
TThreadId id=static_cast<CServShutdownSession*>(session)->ClientThreadId();
|
|
358 |
TInt pos;
|
|
359 |
if (clientArray->Find(id,key,pos)!=0)
|
|
360 |
{
|
|
361 |
clientArray->AppendL(id);
|
|
362 |
}
|
|
363 |
}
|
|
364 |
return clientArray;
|
|
365 |
|
|
366 |
|
|
367 |
}
|
|
368 |
|
|
369 |
#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
|
|
370 |
/**
|
|
371 |
This method will write thread id-s of all clients that are registered for shutdown notification in to a streem.
|
|
372 |
@param aMessage consists of buffer, clientside array count and server side array count
|
|
373 |
*/
|
|
374 |
void CServShutdownServer::ClientArrayL(const RMessage2& aMessage)
|
|
375 |
{
|
|
376 |
const TInt arrayItemCount = ClientArrayCount();
|
|
377 |
//write all registered client array in a buffer only when client side
|
|
378 |
//array count is equal to server side array count
|
|
379 |
if(arrayItemCount == aMessage.Int1())
|
|
380 |
{
|
|
381 |
const TInt sizeRequired = arrayItemCount * sizeof(TThreadId);
|
|
382 |
CBufFlat* const buf=CBufFlat::NewL(sizeRequired);
|
|
383 |
CleanupStack::PushL(buf);
|
|
384 |
RBufWriteStream writeStream(*buf);
|
|
385 |
CleanupClosePushL(writeStream);
|
|
386 |
TDblQueIter<CSession2> iter(iSessionIter);
|
|
387 |
iter.SetToFirst();
|
|
388 |
for (CSession2* session=iter++; session!=NULL; session=iter++)
|
|
389 |
{
|
|
390 |
TThreadId id=static_cast<CServShutdownSession*>(session)->ClientThreadId();
|
|
391 |
//Thread id (which is TUint64) is broken in to two TUint32 and written as RWriteStream doesnt
|
|
392 |
//support TUint64. Client API will recreate TUint64 value from these TUint32 values.
|
|
393 |
if(id.Id())
|
|
394 |
{
|
|
395 |
//RWriteStream there is no API to writes a TUint64 value as a 64 bit value to stream
|
|
396 |
writeStream.WriteUint32L(I64HIGH(id.Id()));
|
|
397 |
writeStream.WriteUint32L(I64LOW(id.Id()));
|
|
398 |
}
|
|
399 |
}
|
|
400 |
writeStream.CommitL();
|
|
401 |
aMessage.WriteL(0, buf->Ptr(0));
|
|
402 |
CleanupStack::PopAndDestroy(2,buf); //writeStream, buf
|
|
403 |
}
|
|
404 |
else
|
|
405 |
{
|
|
406 |
aMessage.Write(2, TPckg<TInt>(arrayItemCount));
|
|
407 |
}
|
|
408 |
|
|
409 |
}
|
|
410 |
|
|
411 |
/**
|
|
412 |
This method will return the number of client that are registered for Shutdown notification with ShutDown server.
|
|
413 |
@return Number of registered clients.
|
|
414 |
*/
|
|
415 |
TInt CServShutdownServer::ClientArrayCount()
|
|
416 |
{
|
|
417 |
TDblQueIter<CSession2> iter(iSessionIter);
|
|
418 |
iter.SetToFirst();
|
|
419 |
TInt count =0;
|
|
420 |
for (CSession2* session=iter++; session!=NULL; session=iter++)
|
|
421 |
{
|
|
422 |
TThreadId id=static_cast<CServShutdownSession*>(session)->ClientThreadId();
|
|
423 |
//Clients which are not registered for notification will not have RMessage in the session and hence
|
|
424 |
//thread id will be NULL(e.g.CLafShutdownEventObserverAdaptor). Avoid such clients.
|
|
425 |
if(id.Id())
|
|
426 |
{
|
|
427 |
++count;
|
|
428 |
}
|
|
429 |
}
|
|
430 |
return count;
|
|
431 |
}
|
|
432 |
#endif //SYMBIAN_SSM_GRACEFUL_SHUTDOWN
|
|
433 |
/**
|
|
434 |
@return Non-zero, if all registered clients have pending requests.
|
|
435 |
*/
|
|
436 |
TBool CServShutdownServer::AllSessionsHavePendingRequest() const
|
|
437 |
{
|
|
438 |
TBool ret=ETrue;
|
|
439 |
TDblQueIter<CSession2> iter(iSessionIter);
|
|
440 |
iter.SetToFirst();
|
|
441 |
for (CSession2* session=iter++; session!=NULL; session=iter++)
|
|
442 |
{
|
|
443 |
const CServShutdownSession* mySession=static_cast<CServShutdownSession*>(session);
|
|
444 |
if (!mySession->HasPendingRequest())
|
|
445 |
{
|
|
446 |
ret=EFalse;
|
|
447 |
break;
|
|
448 |
}
|
|
449 |
}
|
|
450 |
return ret;
|
|
451 |
}
|
|
452 |
|
|
453 |
|
|
454 |
/**
|
|
455 |
@param aId Client's thread id.
|
|
456 |
@return Non-zero if the client with this thread id has no pending request.
|
|
457 |
*/
|
|
458 |
EXPORT_C TBool CServShutdownServer::IsClientHung(TThreadId aId) const
|
|
459 |
{
|
|
460 |
TBool ret=EFalse;
|
|
461 |
TDblQueIter<CSession2> iter(iSessionIter);
|
|
462 |
iter.SetToFirst();
|
|
463 |
for (CSession2* session=iter++; session!=NULL; session=iter++)
|
|
464 |
{
|
|
465 |
const CServShutdownSession* mySession=static_cast<CServShutdownSession*>(session);
|
|
466 |
|
|
467 |
if (mySession->ClientThreadId()==aId)
|
|
468 |
{
|
|
469 |
if (!mySession->HasPendingRequest())
|
|
470 |
{
|
|
471 |
ret=ETrue;
|
|
472 |
break;
|
|
473 |
}
|
|
474 |
}
|
|
475 |
}
|
|
476 |
return ret;
|
|
477 |
}
|
|
478 |
|
|
479 |
//
|
|
480 |
// class CServShutdownSession
|
|
481 |
//
|
|
482 |
|
|
483 |
/**
|
|
484 |
*/
|
|
485 |
EXPORT_C CServShutdownSession::CServShutdownSession()
|
|
486 |
: CSession2(),
|
|
487 |
iCurrentEvent(-1), iOutstandingEvent(-1)
|
|
488 |
{}
|
|
489 |
|
|
490 |
/**
|
|
491 |
*/
|
|
492 |
EXPORT_C CServShutdownSession::~CServShutdownSession()
|
|
493 |
{
|
|
494 |
}
|
|
495 |
|
|
496 |
/**
|
|
497 |
Standard phase-one factor method for creating CServShutdownSession instances.
|
|
498 |
@return A pointer to the created CServShutdownSession instance.
|
|
499 |
@leave KErrNoMemory Not enough memory to complete the operation.
|
|
500 |
*/
|
|
501 |
CServShutdownSession* CServShutdownSession::NewL()
|
|
502 |
{
|
|
503 |
return new (ELeave) CServShutdownSession;
|
|
504 |
}
|
|
505 |
|
|
506 |
/**
|
|
507 |
@return Non-zero, if the client has a pending request.
|
|
508 |
*/
|
|
509 |
TBool CServShutdownSession::HasPendingRequest() const
|
|
510 |
{
|
|
511 |
return !iPtr.IsNull();
|
|
512 |
}
|
|
513 |
|
|
514 |
/**
|
|
515 |
This method will complete the pending asychronous client request, effectivelly notifying it
|
|
516 |
about the action, which the client has to do.
|
|
517 |
@param aSaveType The type of the requested save action.
|
|
518 |
*/
|
|
519 |
void CServShutdownSession::NotifySave(MSaveObserver::TSaveType aSaveType)
|
|
520 |
{
|
|
521 |
const TInt saveType=(TInt)aSaveType;
|
|
522 |
if (HasPendingRequest())
|
|
523 |
{
|
|
524 |
iPtr.Complete(saveType);
|
|
525 |
iCurrentEvent=saveType;
|
|
526 |
}
|
|
527 |
else
|
|
528 |
{
|
|
529 |
if (iCurrentEvent==(TInt)MSaveObserver::ESaveAll ||
|
|
530 |
(iCurrentEvent==(TInt)MSaveObserver::ESaveQuick &&
|
|
531 |
aSaveType==MSaveObserver::ESaveData))
|
|
532 |
{
|
|
533 |
iOutstandingEvent=saveType;
|
|
534 |
}
|
|
535 |
}
|
|
536 |
}
|
|
537 |
|
|
538 |
/**
|
|
539 |
This method dispatches all client requests to the appropriate method calls.
|
|
540 |
@param aMessage The client's message
|
|
541 |
@param aCompleteRequest An output parameter. If zero, the client request
|
|
542 |
will be completed later.
|
|
543 |
*/
|
|
544 |
void CServShutdownSession::DoServiceL(const RMessage2& aMessage, TBool& aCompleteRequest)
|
|
545 |
{
|
|
546 |
switch (aMessage.Function())
|
|
547 |
{
|
|
548 |
case TSaveOpCodeNotify:
|
|
549 |
RequestNotifyPowerDown(aMessage);
|
|
550 |
// don't complete async message yet
|
|
551 |
aCompleteRequest=EFalse;
|
|
552 |
break;
|
|
553 |
case TSaveOpCodeNotifyCancel:
|
|
554 |
RequestNotifyPowerDownCancel();
|
|
555 |
break;
|
|
556 |
case TSaveOpCodeHandleError:
|
|
557 |
User::Leave(KErrNotSupported);
|
|
558 |
break;
|
|
559 |
case TSaveOpCodePowerOff:
|
|
560 |
PowerOffL(aMessage);
|
|
561 |
break;
|
|
562 |
case TSaveOpCodeQueryPowerState:
|
|
563 |
PowerStateL(aMessage);
|
|
564 |
break;
|
|
565 |
#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
|
|
566 |
case EEventObsAdaptHandleShutdown:
|
|
567 |
case EEventObsAdaptClientArrayCount:
|
|
568 |
case EEventObsAdaptClientArray:
|
|
569 |
case EEventObsAdaptIsClientHung:
|
|
570 |
case EEventObsAdaptGetShutdownState:
|
|
571 |
{
|
|
572 |
if (IsSsmGracefulShutdown()) // SSM should be used for device shutdown
|
|
573 |
{
|
|
574 |
switch(aMessage.Function())
|
|
575 |
{
|
|
576 |
case EEventObsAdaptHandleShutdown:
|
|
577 |
HandleShutdownEventL(aMessage);
|
|
578 |
break;
|
|
579 |
case EEventObsAdaptClientArrayCount:
|
|
580 |
ClientArrayCount(aMessage);
|
|
581 |
break;
|
|
582 |
case EEventObsAdaptClientArray:
|
|
583 |
ClientArrayL(aMessage);
|
|
584 |
break;
|
|
585 |
case EEventObsAdaptIsClientHung:
|
|
586 |
IsClientHung(aMessage);
|
|
587 |
break;
|
|
588 |
case EEventObsAdaptGetShutdownState:
|
|
589 |
GetShutdownState(aMessage);
|
|
590 |
break;
|
|
591 |
}
|
|
592 |
}
|
|
593 |
break;
|
|
594 |
}
|
|
595 |
#endif // SYMBIAN_SSM_GRACEFUL_SHUTDOWN
|
|
596 |
default:
|
|
597 |
User::Leave(KErrNotSupported);
|
|
598 |
break;
|
|
599 |
}
|
|
600 |
}
|
|
601 |
|
|
602 |
#ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN
|
|
603 |
|
|
604 |
void CServShutdownSession::HandleShutdownEventL(const RMessage2& aMessage)
|
|
605 |
{
|
|
606 |
MSaveObserver::TSaveType action = static_cast <MSaveObserver::TSaveType> (aMessage.Int0());
|
|
607 |
TBool powerOff = static_cast <TBool> (aMessage.Int1());
|
|
608 |
TPowerState powerEvent = static_cast <TPowerState> (aMessage.Int2());
|
|
609 |
|
|
610 |
CServShutdownServer* server = static_cast<CServShutdownServer*>(const_cast<CServer2*>(Server()));
|
|
611 |
server->HandleShutdownEventL(action, powerOff, powerEvent);
|
|
612 |
}
|
|
613 |
|
|
614 |
void CServShutdownSession::ClientArrayCount(const RMessage2& aMessage) const
|
|
615 |
{
|
|
616 |
CServShutdownServer* server = static_cast<CServShutdownServer*>(const_cast<CServer2*>(Server()));
|
|
617 |
const TInt count = server->ClientArrayCount();
|
|
618 |
aMessage.Write(0, TPckg<TInt>(count));
|
|
619 |
}
|
|
620 |
/*
|
|
621 |
This function will write all registered client array in a buffer only when client side array count is equal to server side array count
|
|
622 |
else aMessage will contain an empty buffer and server side array count .
|
|
623 |
@param aMessage consists of buffer, clientside array count and server side array count
|
|
624 |
*/
|
|
625 |
void CServShutdownSession::ClientArrayL(const RMessage2& aMessage)
|
|
626 |
{
|
|
627 |
CServShutdownServer* server = static_cast<CServShutdownServer*>(const_cast<CServer2*>(Server()));
|
|
628 |
server->ClientArrayL(aMessage);
|
|
629 |
}
|
|
630 |
|
|
631 |
void CServShutdownSession::IsClientHung(const RMessage2& aMessage) const
|
|
632 |
{
|
|
633 |
CServShutdownServer* server = static_cast<CServShutdownServer*>(const_cast<CServer2*>(Server()));
|
|
634 |
TThreadId threadId = static_cast <TThreadId>(aMessage.Int0());
|
|
635 |
TBool clientHung = server->IsClientHung(threadId);
|
|
636 |
|
|
637 |
aMessage.Write(1, TPckg<TBool>(clientHung));
|
|
638 |
}
|
|
639 |
|
|
640 |
void CServShutdownSession::GetShutdownState(const RMessage2& aMessage) const
|
|
641 |
{
|
|
642 |
TBool powerOff;
|
|
643 |
TBool allSessionsHavePendingRequest;
|
|
644 |
|
|
645 |
CServShutdownServer* server = static_cast<CServShutdownServer*>(const_cast<CServer2*>(Server()));
|
|
646 |
server->GetShutdownState(powerOff, allSessionsHavePendingRequest);
|
|
647 |
aMessage.Write(0, TPckg<TBool>(powerOff));
|
|
648 |
aMessage.Write(1, TPckg<TBool>(allSessionsHavePendingRequest));
|
|
649 |
}
|
|
650 |
|
|
651 |
#endif //SYMBIAN_SSM_GRACEFUL_SHUTDOWN
|
|
652 |
|
|
653 |
/**
|
|
654 |
Handles the servicing of client requests passed to the shutdown server.
|
|
655 |
@param aMessage The message containing the client request.
|
|
656 |
*/
|
|
657 |
EXPORT_C void CServShutdownSession::ServiceL(const RMessage2& aMessage)
|
|
658 |
{
|
|
659 |
TBool aCompleteRequest=ETrue;
|
|
660 |
TRAPD(error, DoServiceL(aMessage, aCompleteRequest));
|
|
661 |
if (aCompleteRequest)
|
|
662 |
{
|
|
663 |
aMessage.Complete(error);
|
|
664 |
}
|
|
665 |
}
|
|
666 |
|
|
667 |
/**
|
|
668 |
This method processes a client-side registration request. It is an asynchronous request,
|
|
669 |
which will be completed later, when powerdown/low memory event occurs.
|
|
670 |
@param aMessage The message containing the client request.
|
|
671 |
*/
|
|
672 |
void CServShutdownSession::RequestNotifyPowerDown(const RMessage2& aMessage)
|
|
673 |
{
|
|
674 |
iCurrentEvent=-1;
|
|
675 |
iPtr = aMessage;
|
|
676 |
|
|
677 |
if (iOutstandingEvent!=-1)
|
|
678 |
{
|
|
679 |
NotifySave((MSaveObserver::TSaveType)iOutstandingEvent);
|
|
680 |
iOutstandingEvent=-1;
|
|
681 |
}
|
|
682 |
//The thread variable is just a dummy variable(input for CServShutdownServer::HandlePowerNotifRequest)
|
|
683 |
//and is not used inside the function at all, it is there to preserve BC.
|
|
684 |
RThread thread;
|
|
685 |
static_cast<CServShutdownServer*>(const_cast<CServer2*>(Server()))->HandlePowerNotifRequest(thread);
|
|
686 |
}
|
|
687 |
|
|
688 |
/**
|
|
689 |
This method cancels the client registration, completing the requests with
|
|
690 |
KErrCancel error code.
|
|
691 |
*/
|
|
692 |
void CServShutdownSession::RequestNotifyPowerDownCancel()
|
|
693 |
{
|
|
694 |
if (HasPendingRequest())
|
|
695 |
iPtr.Complete(KErrCancel);
|
|
696 |
}
|
|
697 |
|
|
698 |
/**
|
|
699 |
@return The client's thread id.
|
|
700 |
*/
|
|
701 |
TThreadId CServShutdownSession::ClientThreadId() const
|
|
702 |
{
|
|
703 |
TThreadId id = NULL;
|
|
704 |
RThread clientThread;
|
|
705 |
//Clients which are not registered for notification will not have RMessage in the session and hence
|
|
706 |
//thread id will be NULL(e.g.CLafShutdownEventObserverAdaptor). Avoid such clients.
|
|
707 |
if(!iPtr.IsNull() && KErrNone == iPtr.Client(clientThread))
|
|
708 |
{
|
|
709 |
id = clientThread.Id();
|
|
710 |
}
|
|
711 |
clientThread.Close();
|
|
712 |
return id;
|
|
713 |
}
|
|
714 |
|
|
715 |
|
|
716 |
/**
|
|
717 |
This method should be used only with SYSLIBS_TEST macro defined and can be used to
|
|
718 |
initiate a powerdown sequence.
|
|
719 |
Without SYSLIBS_TEST macro defined the method will panic the client with
|
|
720 |
KErrNotSupported error code.
|
|
721 |
@param aMessage The message containing the client request.
|
|
722 |
*/
|
|
723 |
#ifdef SYSLIBS_TEST
|
|
724 |
void CServShutdownSession::PowerOffL(const RMessage2& aMessage)
|
|
725 |
{
|
|
726 |
MSaveObserver::TSaveType action = static_cast <MSaveObserver::TSaveType> (aMessage.Int0());
|
|
727 |
TBool powerOff = static_cast <TBool> (aMessage.Int1());
|
|
728 |
CServShutdownServer* server = static_cast<CServShutdownServer*>(const_cast<CServer2*>(Server()));
|
|
729 |
server->HandleShutdownEventL(action, powerOff);
|
|
730 |
}
|
|
731 |
#else
|
|
732 |
void CServShutdownSession::PowerOffL(const RMessage2& aMessage)
|
|
733 |
{
|
|
734 |
aMessage.Panic(__SHUTDOWN_SERVER_NAME, KErrNotSupported);
|
|
735 |
}
|
|
736 |
#endif//SYSLIBS_TEST
|
|
737 |
|
|
738 |
/**
|
|
739 |
This method should be used only with SYSLIBS_TEST macro defined and can be used to
|
|
740 |
get the power state of the server.
|
|
741 |
Without SYSLIBS_TEST macro defined the method will panic the client with
|
|
742 |
KErrNotSupported error code.
|
|
743 |
@param aMessage The message containing the client request.
|
|
744 |
*/
|
|
745 |
#ifdef SYSLIBS_TEST
|
|
746 |
void CServShutdownSession::PowerStateL(const RMessage2& aMessage) const
|
|
747 |
{
|
|
748 |
CServShutdownServer* server = static_cast<CServShutdownServer*>(const_cast<CServer2*>(Server()));
|
|
749 |
TBool powerOff = server->IsPowerOff();
|
|
750 |
TPckg<TBool> powerOffPckg(powerOff);
|
|
751 |
aMessage.WriteL(0,powerOffPckg);
|
|
752 |
}
|
|
753 |
#else
|
|
754 |
void CServShutdownSession::PowerStateL(const RMessage2& aMessage) const
|
|
755 |
{
|
|
756 |
aMessage.Panic(__SHUTDOWN_SERVER_NAME, KErrNotSupported);
|
|
757 |
}
|
|
758 |
#endif//SYSLIBS_TEST
|
|
759 |
|