|
1 // Copyright (c) 2007-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 <barsc2.h> |
|
17 #include <barsread2.h> |
|
18 #include <e32property.h> |
|
19 #include <e32uid.h> |
|
20 #include <e32std.h> |
|
21 #include <bautils.h> |
|
22 |
|
23 #include <ssm/ssmcmd.hrh> |
|
24 #include <ssm/ssmsubstates.hrh> |
|
25 #ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN |
|
26 #include <ssm/ssmpatchableconstants.h> |
|
27 #include <ssm/conditiontypes.hrh> |
|
28 #endif |
|
29 |
|
30 #include <ssm/ssmstatetransition.h> |
|
31 #include <ssm/ssmcommandlistresourcereader.h> |
|
32 #include <ssm/ssmmaxbootattempts_patch.h> |
|
33 |
|
34 #include "gsastatepolicystartup.h" |
|
35 #include "ssmdebug.h" |
|
36 #include "ssmpanic.h" |
|
37 #include "s32file.h" |
|
38 |
|
39 _LIT(KBootUpFile, ":\\private\\2000d75b\\bootupinfo\\bootupcount.bin"); |
|
40 |
|
41 /** |
|
42 Attempt to reboot the device (forever) on boot failure. Used when KSsmMaxBootAttempts is set to '0xFFFFFFFF'. |
|
43 */ |
|
44 const TInt KSsmAttemptRebootForever = 0xFFFFFFFF; |
|
45 |
|
46 /** |
|
47 Panic used by Startup policy plug-in when resource reader is invalid. |
|
48 Strings must not be longer than 16 characters or they will be truncated by User::Panic() |
|
49 */ |
|
50 _LIT(KPanicGsaStartupState, "StartupPolicy"); |
|
51 |
|
52 /** |
|
53 Start-up state policy resource file path format : "z:/private/<SID of SSM>/startup/<Value of KSystemStartupModeKey>/" |
|
54 */ |
|
55 _LIT(KCommandListPath, "z:\\private\\2000D75B\\startup\\%d\\"); |
|
56 |
|
57 /** |
|
58 Commandlist path to launch 'sysstart.exe' when a resource file for 'start-up' is not found. |
|
59 fallback to 'sysstart.exe' resource file path format : "z:/private/<SID of SSM>/startup/fallback/" |
|
60 */ |
|
61 _LIT(KFallbackCmdListPath, "z:\\private\\2000D75B\\startup\\fallback\\"); |
|
62 |
|
63 /** |
|
64 Used to create an instance of MSsmStatePolicy class. |
|
65 |
|
66 @return A pointer to an instance of MSsmStatePolicy |
|
67 */ |
|
68 EXPORT_C MSsmStatePolicy* CGsaStatePolicyStartup::NewL() |
|
69 { |
|
70 CGsaStatePolicyStartup* self = new (ELeave) CGsaStatePolicyStartup; |
|
71 CleanupStack::PushL(self); |
|
72 self->ConstructL(); |
|
73 CleanupStack::Pop(self); |
|
74 return self; |
|
75 } |
|
76 |
|
77 /** |
|
78 Gets the hardware reason for KSystemStartupModeKey and makes a RFs connection. |
|
79 Creates Command list path and the resource reader for startup. |
|
80 |
|
81 @leave One of the error value returned by |
|
82 RProperty::Get() |
|
83 RFs::Connect() |
|
84 RArray::AppendL() |
|
85 NewL() |
|
86 @see RProperty::Get |
|
87 */ |
|
88 void CGsaStatePolicyStartup::ConstructL() |
|
89 { |
|
90 // Read the hardware reason |
|
91 User::LeaveIfError(RProperty::Get(KUidSystemCategory, KSystemStartupModeKey, iHardwareReason)); |
|
92 User::LeaveIfError(iFs.Connect()); |
|
93 |
|
94 // Add supported transitions from Startup 'ESsmStartup' |
|
95 iCurrentlySupportedTransitions.AppendL(TSsmState(ESsmFail, KSsmAnySubState)); |
|
96 iCurrentlySupportedTransitions.AppendL(TSsmState(ESsmShutdown, KSsmAnySubState)); |
|
97 iCurrentlySupportedTransitions.AppendL(TSsmState(ESsmShutdown, ESsmShutdownSubStateCritical)); |
|
98 |
|
99 TFileName cmdListPath; |
|
100 GetCommandListPath(iHardwareReason, cmdListPath); |
|
101 DEBUGPRINT2(_L("Startup Policy : Startup command list path : %S"), &cmdListPath); |
|
102 |
|
103 // create resource reader |
|
104 iCommandListResourceReader = CSsmCommandListResourceReader::NewL(iFs, cmdListPath, *this); |
|
105 } |
|
106 |
|
107 /** |
|
108 default CTOR |
|
109 */ |
|
110 CGsaStatePolicyStartup::CGsaStatePolicyStartup() |
|
111 { |
|
112 } |
|
113 |
|
114 /** |
|
115 DTOR |
|
116 */ |
|
117 CGsaStatePolicyStartup::~CGsaStatePolicyStartup() |
|
118 { |
|
119 delete iCommandListResourceReader; |
|
120 iSubStates.Close(); |
|
121 iFs.Close(); |
|
122 iCurrentlySupportedTransitions.Close(); |
|
123 } |
|
124 |
|
125 /** |
|
126 Initializes command list resource reader. |
|
127 |
|
128 @param aStatus to complete when the initialization operation has finished |
|
129 @panic EInvalidResourceReader if the command list resource reader is invalid |
|
130 |
|
131 @see MSsmStatePolicy::Initialize |
|
132 */ |
|
133 void CGsaStatePolicyStartup::Initialize(TRequestStatus& aStatus) |
|
134 { |
|
135 __ASSERT_DEBUG(iCommandListResourceReader, PanicNow(KPanicGsaStartupState, EInvalidResourceReader)); |
|
136 |
|
137 // initialise command list resource reader. |
|
138 iCommandListResourceReader->Initialise(aStatus); |
|
139 } |
|
140 |
|
141 /** |
|
142 Cancels an asynchronous Initialize operation. |
|
143 |
|
144 @see MSsmStatePolicy::InitializeCancel |
|
145 */ |
|
146 void CGsaStatePolicyStartup::InitializeCancel() |
|
147 { |
|
148 iCommandListResourceReader->InitialiseCancel(); |
|
149 } |
|
150 |
|
151 /** |
|
152 Deletes all resources and frees itself. |
|
153 |
|
154 @see MSsmStatePolicy::Release |
|
155 */ |
|
156 void CGsaStatePolicyStartup::Release() |
|
157 { |
|
158 delete this; |
|
159 } |
|
160 |
|
161 /** |
|
162 Determines if an incoming startup state transition request should be accepted or rejected. |
|
163 Clients calling this API should posess 'ECapabilityPowerMgmt', else the API will return ENotAllowed. |
|
164 |
|
165 @param aRequest Contains information about the new request |
|
166 @param aCurrent Contains NULL or the first accepted but not yet completed transition request |
|
167 @param aQueued Contains NULL or a second accepted but not yet started transition request |
|
168 @param aMessage Message sent by SSM server, used to check if the client has 'ECapabilityPowerMgmt' |
|
169 |
|
170 @return one of the TResponse value |
|
171 @see MSsmStatePolicy::TransitionAllowed |
|
172 @see MSsmStatePolicy::TResponse |
|
173 */ |
|
174 MSsmStatePolicy::TResponse CGsaStatePolicyStartup::TransitionAllowed(const TSsmStateTransition& aRequest, TSsmStateTransition const* aCurrent, |
|
175 TSsmStateTransition const* aQueued, const RMessagePtr2& aMessage) |
|
176 { |
|
177 TResponse response = ENotAllowed; |
|
178 if (!aMessage.HasCapability(ECapabilityPowerMgmt)) |
|
179 { |
|
180 DEBUGPRINT1(_L ("Startup Policy : Capability Check Failed.")); |
|
181 return response; |
|
182 } |
|
183 |
|
184 //Check if the requested transition is supported from current state |
|
185 if(TransitionSupported(aRequest.State())) |
|
186 { |
|
187 if((NULL == aCurrent) && (NULL == aQueued)) |
|
188 { |
|
189 // SsmServer is idle |
|
190 response = EDefinitelyAllowed; |
|
191 } |
|
192 else if((aRequest.State().MainState() == ESsmFail) || (aRequest.State().MainState() == ESsmShutdown)) |
|
193 { |
|
194 // Going into failed state or shutdown state will override anything currently ongoing or queued |
|
195 response = EReplaceCurrentClearQueue; |
|
196 } |
|
197 } |
|
198 |
|
199 #ifdef _DEBUG |
|
200 TSsmStateName name = aRequest.State().Name(); |
|
201 if(ENotAllowed == response) |
|
202 { |
|
203 DEBUGPRINT3(_L("Startup Policy : Transition (Requested State: %S) is not allowed (Response: %d)."), &name, response); |
|
204 } |
|
205 else |
|
206 { |
|
207 DEBUGPRINT3(_L("Startup Policy : Transition (Requested State %S) is allowed (Response %d)."), &name, response); |
|
208 } |
|
209 #endif |
|
210 return response; |
|
211 } |
|
212 |
|
213 /** |
|
214 Create the command list associated with a sub state transition. |
|
215 |
|
216 @param aState Contains the state and substate that identifies the command list to create |
|
217 @param aReason Contains the reason as given by the request |
|
218 @param aStatus to complete when the operation has finished |
|
219 @panic EInvalidResourceReader if the command list resource reader is invalid |
|
220 @see MSsmStatePolicy::PrepareCommandList |
|
221 */ |
|
222 void CGsaStatePolicyStartup::PrepareCommandList(TSsmState aState, TInt aReason, TRequestStatus& aStatus) |
|
223 { |
|
224 __ASSERT_DEBUG(iCommandListResourceReader, PanicNow(KPanicGsaStartupState, EInvalidResourceReader)); |
|
225 |
|
226 iSoftwareReason = aReason; |
|
227 |
|
228 //Let's start from the beginning if no specific minor state is selected |
|
229 iRequestedSubState = ((aState.SubState() == KSsmAnySubState) ? ESsmStartupSubStateCriticalStatic : aState.SubState()); |
|
230 TSsmState publishState; |
|
231 publishState.Set(aState.MainState(), iRequestedSubState); |
|
232 |
|
233 const TInt commandListId = publishState.SubState(); |
|
234 |
|
235 //Build the commandlist from resource |
|
236 iCommandListResourceReader->PrepareCommandList(commandListId, publishState, aStatus); |
|
237 } //lint !e1746 Suppress parameter 'aState' could be made const reference |
|
238 |
|
239 /** |
|
240 Cancels asynchronous PrepareCommandList operation. |
|
241 |
|
242 @see MSsmStatePolicy::PrepareCommandListCancel |
|
243 */ |
|
244 void CGsaStatePolicyStartup::PrepareCommandListCancel() |
|
245 { |
|
246 iCommandListResourceReader->PrepareCommandListCancel(); |
|
247 } |
|
248 |
|
249 /** |
|
250 Return the command list once the PrepareCommandList has completed. |
|
251 Ownership of the returned command list is transferred to the caller. |
|
252 @panic EInvalidResourceReader if the command list resource reader is invalid |
|
253 @return The command list created during the preceding PrepareCommandList step |
|
254 */ |
|
255 CSsmCommandList* CGsaStatePolicyStartup::CommandList() |
|
256 { |
|
257 __ASSERT_DEBUG(iCommandListResourceReader , PanicNow(KPanicGsaStartupState, EInvalidResourceReader)); |
|
258 |
|
259 return iCommandListResourceReader->GetCommandList(); |
|
260 } |
|
261 |
|
262 /** |
|
263 Determines the next sub state transition. |
|
264 @param aCurrentTransition Contains the last executed state |
|
265 @param aReason Contains the reason as given by the request |
|
266 @param aError Contains the completion code from the last executed sub-state transition |
|
267 @param aSeverity Contains the severity of the failed command in case the sub-state transition ended with an error |
|
268 @param aNextState The next System State to head for, if there is one |
|
269 @panic EInvalidStartupstate if the current state is not startup |
|
270 @return ETrue if aNextState contains another System State to head for, or |
|
271 EFalse if there is no further transitions to do. |
|
272 @see MSsmStatePolicy::GetNextState |
|
273 */ |
|
274 TBool CGsaStatePolicyStartup::GetNextState(TSsmState aCurrentTransition, TInt /*aReason*/, TInt aError, TInt /*aSeverity*/, TSsmState& aNextState) |
|
275 { |
|
276 __ASSERT_ALWAYS(aCurrentTransition.MainState() == ESsmStartup, PanicNow(KPanicGsaStartupState, EInvalidStartupState)); |
|
277 |
|
278 if (KErrNone != aError) // Handle CLE error here |
|
279 { |
|
280 if (iLaunchSysStart) // 'sysstart.exe' was launched unsuccessfully so launch 'sysagt2srv.exe' and 'wserv.exe' |
|
281 { |
|
282 iLaunchSysStart = EFalse; |
|
283 iLaunchSysAgt2SrvAndWServ = ETrue; |
|
284 DEBUGPRINT2(_L("Startup Policy : sysstart.exe launched with error : %d"), aError); |
|
285 aNextState = TSsmState(ESsmStartup, ESsmStartupSubStateCriticalDynamic); |
|
286 return ETrue; |
|
287 } |
|
288 |
|
289 #ifdef __WINS__ // on emulator |
|
290 { |
|
291 DEBUGPRINT2(_L("Startup Policy : CLE returned with (error : %d), Panic on Emulator"), aError); |
|
292 DEBUGPRINT1(_L("Startup Policy : Emulator (__WINS__) does not support a re-start, so Fail Policy is not invoked.")); |
|
293 PanicNow(KPanicGsaStartupState, EEmulatorPowerOff); |
|
294 } |
|
295 #else // on hardware/device |
|
296 { |
|
297 aNextState = TSsmState(ESsmFail, ESsmFailSubStateRestart); |
|
298 if (KSsmAttemptRebootForever != KSsmMaxBootAttempts) |
|
299 { |
|
300 // Get number of boot attempts made till now from bootup log file |
|
301 TInt bootCount = -1; |
|
302 TRAPD(err, bootCount = GetBootupCountL()); // ignore failure and restart the device, we should get the value next time. |
|
303 if (err!=KErrNone) |
|
304 { |
|
305 DEBUGPRINT2(_L("Startup Policy : GetBootupCountL() failed with (error: %d), error is deliberately ignored."), aError); |
|
306 } |
|
307 if (bootCount < KSsmMaxBootAttempts) |
|
308 { |
|
309 aNextState = TSsmState(ESsmFail, ESsmFailSubStateRestart); |
|
310 } |
|
311 else // Maximum allowed boot attempts has been made. Device needs a poweroff. Probable candidate for a reset/reflash. |
|
312 { |
|
313 aNextState = TSsmState(ESsmFail, ESsmFailSubStatePowerOff); |
|
314 } |
|
315 } |
|
316 #ifdef _DEBUG |
|
317 TSsmStateName name = aNextState.Name(); |
|
318 DEBUGPRINT3(_L("Startup Policy : CLE returned with (error : %d) so moving to Fail State : %S."), aError, &name); |
|
319 #endif |
|
320 return ETrue; |
|
321 } |
|
322 #endif |
|
323 } |
|
324 else if(iLaunchSysStart || iLaunchSysAgt2SrvAndWServ) // If either sysstart or sysagt2srv and wserv was launched and CLE did not return an error |
|
325 { |
|
326 if (iLaunchSysStart) |
|
327 { |
|
328 iLaunchSysStart = EFalse; |
|
329 DEBUGPRINT1(_L("Startup Policy : sysstart.exe launched successfully.")); |
|
330 } |
|
331 if (iLaunchSysAgt2SrvAndWServ) |
|
332 { |
|
333 iLaunchSysAgt2SrvAndWServ = EFalse; |
|
334 DEBUGPRINT1(_L("Startup Policy : sysagt2srv.exe and wserv.exe launched successfully.")); |
|
335 } |
|
336 aNextState = TSsmState(ESsmNormal, KSsmAnySubState); // move to Normal state |
|
337 return ETrue; |
|
338 } |
|
339 else // have to move one with the next substates in this state |
|
340 { |
|
341 // Get the sub states from resource reader only once |
|
342 if (!iSubStatesCount) |
|
343 { |
|
344 // Get sub states list from resource reader |
|
345 TRAPD(err, iCommandListResourceReader->GetCommandListIdsL(iSubStates)); |
|
346 if (err) |
|
347 { |
|
348 DEBUGPRINT2(_L("Startup Policy : Command list ids prepared with error: %d"), err); |
|
349 } |
|
350 else |
|
351 { |
|
352 iSubStatesCount = iSubStates.Count(); |
|
353 } |
|
354 } |
|
355 |
|
356 TInt index = iSubStates.Find(iRequestedSubState); |
|
357 |
|
358 if (KErrNotFound == index) |
|
359 { |
|
360 DEBUGPRINT2(_L("Startup Policy : SubState for transition not found: %d"), index); |
|
361 PanicNow(KPanicGsaStartupState, ESubStateIndexNotFound); |
|
362 } |
|
363 else if (index == (iSubStatesCount - 1)) // transition complete, move to Normal state |
|
364 { |
|
365 TInt retVal = EFalse; |
|
366 // moving to next state as the transition is completed for ESsmStartup |
|
367 if (iSubStatesCount && (iRequestedSubState == iSubStates[iSubStatesCount-1])) |
|
368 { |
|
369 aNextState = TSsmState(ESsmNormal, KSsmAnySubState); |
|
370 retVal = ETrue; |
|
371 } |
|
372 return retVal; |
|
373 } |
|
374 else // there is a substate available for transition, moved ahead |
|
375 { |
|
376 iRequestedSubState = iSubStates[++index]; |
|
377 aNextState = TSsmState(ESsmStartup, iRequestedSubState); |
|
378 #ifdef _DEBUG |
|
379 TSsmStateName name = aNextState.Name(); |
|
380 DEBUGPRINT2(_L("Startup Policy : Transition to next state is : %S"), &name); |
|
381 #endif |
|
382 return ETrue; |
|
383 } |
|
384 } |
|
385 return EFalse; |
|
386 } //lint !e1746 Suppress parameter 'aCurrentTransition' could be made const reference |
|
387 |
|
388 /** |
|
389 Callback used by CSsmCommandListResourceReader when a decision needs to be made |
|
390 on whether to include a command in a command list or not. |
|
391 |
|
392 @param aResourceFile Instance of CResourceFile |
|
393 @param aResourceId Resource id of SSM_SYMBIAN_CONDITIONAL_INFORMATION struct for command |
|
394 @return ETrue in case the command needs to be included in command list, else EFalse. |
|
395 |
|
396 @see MSsmConditionalCallback::ConditionalCommandAllowedL |
|
397 */ |
|
398 #ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN |
|
399 TBool CGsaStatePolicyStartup::ConditionalCommandAllowedL(CResourceFile& aResourceFile, TInt aResourceId) |
|
400 #else |
|
401 TBool CGsaStatePolicyStartup::ConditionalCommandAllowedL(CResourceFile& /*aResourceFile*/, TInt /*aResourceId*/) |
|
402 #endif |
|
403 { |
|
404 TBool isAllowed = EFalse; |
|
405 #ifdef SYMBIAN_SSM_GRACEFUL_SHUTDOWN |
|
406 HBufC8* buf = aResourceFile.AllocReadLC(aResourceId); |
|
407 TResourceReader reader; |
|
408 reader.SetBuffer(buf); |
|
409 //Read the type of the command from the resource file |
|
410 TUint16 type = reader.ReadUint16(); |
|
411 CleanupStack::PopAndDestroy(buf); |
|
412 // check that the type is equal to "EGracefulShutdown" |
|
413 if(type == EGracefulShutdown) |
|
414 { |
|
415 //Check whether SSM graceful shutdown is enabled or not |
|
416 if(IsSsmGracefulShutdown()) |
|
417 { |
|
418 isAllowed = ETrue; |
|
419 } |
|
420 } |
|
421 #else |
|
422 // no commands use 'conditional_information' in Startup state command list. |
|
423 PanicNow(KPanicGsaStartupState, EConditionalInfoNotImplemented); |
|
424 #endif |
|
425 return isAllowed; |
|
426 } |
|
427 |
|
428 /* |
|
429 Helper function to check whether requested transition is supported or not. |
|
430 */ |
|
431 TBool CGsaStatePolicyStartup::TransitionSupported(const TSsmState& aRequestedState) const |
|
432 { |
|
433 return (iCurrentlySupportedTransitions.Find(aRequestedState) > KErrNotFound); |
|
434 } |
|
435 |
|
436 /* |
|
437 Helper function to create command list path for start-up. |
|
438 Implements fallback mechanism to launch 'sysstart.exe' if static command list for 'start-up' state is not found. |
|
439 This temporary implementation is required during migration from existing 'sysstart' to 'ssma start-up'. |
|
440 */ |
|
441 void CGsaStatePolicyStartup::GetCommandListPath(TUint aBootMode, TDes& aCmdListPath) |
|
442 { |
|
443 aCmdListPath.Format(KCommandListPath, aBootMode); |
|
444 TBool found = BaflUtils::FolderExists(iFs, aCmdListPath); |
|
445 |
|
446 // This Fallback mechanism is used internally during migration from 'sysstart' to 'ssma start-up' and is not required otherwise. |
|
447 if (!found) |
|
448 { |
|
449 aCmdListPath.Copy(KFallbackCmdListPath()); |
|
450 iLaunchSysStart = ETrue; // launch 'sysstart.exe' |
|
451 } |
|
452 } |
|
453 |
|
454 /* |
|
455 Helper function to get the boot count |
|
456 */ |
|
457 TInt CGsaStatePolicyStartup::GetBootupCountL() |
|
458 { |
|
459 RBuf bootupInfoPath; |
|
460 CleanupClosePushL(bootupInfoPath); |
|
461 const TChar drive = RFs::GetSystemDriveChar(); |
|
462 TInt length = KBootUpFile().Length() + 1; /* for RFs::GetSystemDriveChar() */ |
|
463 bootupInfoPath.CreateL(length); |
|
464 bootupInfoPath.Append(drive); |
|
465 bootupInfoPath.Append(KBootUpFile()); |
|
466 TBool found = BaflUtils::FileExists(iFs, bootupInfoPath); |
|
467 if(!found) |
|
468 { |
|
469 User::Leave(EBootupCountFileNotFound); |
|
470 } |
|
471 |
|
472 RFileReadStream file; |
|
473 CleanupClosePushL(file); |
|
474 User::LeaveIfError(file.Open(iFs, bootupInfoPath, EFileRead)); |
|
475 TInt bootCount = file.ReadUint8L(); |
|
476 CleanupStack::PopAndDestroy(&file); |
|
477 CleanupStack::PopAndDestroy(&bootupInfoPath); |
|
478 return bootCount; |
|
479 } |
|
480 |