Category: symbian labs

Cleanup Stack

stackCome si dice: "prima il piacere e poi il dovere…", o una cosa del genere. Dopo il concerto meraviglioso, torniamo sulle pagine di devme, a parlare di cose informatiche spero interessanti. L’argomento di questo post parla di un concetto fondamentale del sistema operativo Symbian, il Cleanup Stack che ha a che fare con la gestione della memoria. Provate a immaginare quanto sia importante poter gestire al meglio una risorsa limitata come la memoria su di un cellulare, non appena la si comincia ad occupare per intero, le prestazioni decadono. Per questo motivo, esiste il Cleanup Stack, ovvero uno stack utilizzato per gestire quegli oggetti che potenzialmente possono generare delle eccezioni (Leave) e che quindi devono liberare la memoria occupata. Consideriamo ad esempio, una variabile locale puntatore ad un oggetto sullo heap, quando accade un eccezione (Leave) il puntatore viene distrutto senza liberare la memoria da esso referenziata, che diventa quindi non più utilizzabile, causando così un memory leak (perdita di memoria). Gli oggetti che non sono leave-safe, dovrebbero -o meglio devono- essere sempre inseriti all’interno del Cleanup Stack in modo da assicurare la loro effettiva distruzione in caso di eccezione. Ad esempio, gli oggetti symbian del tipo di dato C (C object type), sono sempre creati nello heap, non sono leave-safe e quindi vanno sempre inseriti all’interno dello stack. L’esempio seguente mostra alcuni casi di gestione della memoria:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void DevMeUnsafeL() {
    CCDevme* cdevme = new (ELeave) CCDevme;
    /* Metodo InitializaL() potenzialmente pericoloso, può generare.
    * eccezione L'oggetto non è leave-safe, dopo la creazione, in
    * caso di eccezione, né la memoria occupata sullo heap,
    * né eventuali altri oggetti da lui referenziati verranno
    *  distrutti. */
    cdevme->InitializeL();
    delete cdevme;
}
void DevMeSafeButInefficientL() {
    CCDevme* cdevme = new (ELeave) CCDevme;
    /* Per evitare l'eventuale memory leak si può usare
    * la macro TRAPD, ma che per motivi di performance
    * dovrebbe essere evitata. L'uso eccessivo di TRAPD
    * attorno ai metodi non ottimizza la dimensione e la
    * velocità del programma a run-time. */
    TRAPD(cdevme->InitializeL());
    delete cdevme;
}
void DevMeSafeL() {
    CCDevme* cdevme = new (ELeave) CCDevme;
    /* Inserisci all'interno del Cleanup Stack il referimento
    * all'oggetto creato così da poter recuperare la memoria
    * in caso di eccezione. */
    CleanupStack::PushL(cdevme);
    cdevme->InitializeL();
    ......
    ......
    /* Rimuovi dallo stackquando non è più necessario
    *  il riferimento.*/
    CleanupStack::Pop(cdevme);
    delete cdevme;
}

Gli esempi di sopra mostrano alcune possibili gestioni della memoria su Symbian OS e i commenti all’interno degli esempio ne illustrano il funzionamento. E’ chiaro che l’ultimo esempio è il più efficiente dal momento che viene aggiunto nello stack il riferimento dell’oggetto creato e rimosso in caso di eccezione senza creare memory leak e quindi ottimizzando la gestione della memoria. In generale tutti gli oggetti all’interno dello stack vengono correttamente deallocati all’occorrenza, liberando la memoria occupata. La gestione della deallocazione viene fatta dal sistema operativo. Essendo il Cleanup Stack uno stack a tutti gli effetti, la sua gestione segue quella di uno stack normale, e cioè ad ogni Push corrisponde un Pop e l’ordine dei Pop è inverso all’ordine dei Push…..ma questo è già noto vero ?! :P Esistono altri metodi statici che possono essere usati della classe CleanupStack, si rimanda al file di include e32base.h presente all’interno delle SDK di symbian per la descrizione precisa della classe, oppure qui per dare un occhiata alla classe della versione 7.0 di symbian, forse un pò vecchiotta.

Symbian – Auto start di un applicazione

phoneSalve a tutti quei pochi, spero ancora per poco, che leggono il blog…ogni tanto un commentino potreste anche lasciarlo, siamo qui per quello :P !!! Volevo cominciare una, spero lunga serie di post su symbian, il famoso sistema operativo che gira su molti dei cellulati di ultima generazione (nokia, samsung, etc). Per il momento tralasciamo tutto quello che concerne il preliminare di symbian, e vediamo subito, senza perdere tempo, un programmino, o meglio uno scorcio di codice che permette di lanciare un applicazione al boot, ovvero quando si va ad accendere il cellulare.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <apmrec.h>
#include <apmstd.h>
#include "cl_autostart.h" 
const TUid KUidemAclAutostart={0x09A770B5}; CclAutostart::CclAutostart():CApaDataRecognizerType(KUidemAclAutostart, CApaDataRecognizerType::ENormal) {
    iCountDataTypes = 1; 
} 
TUint CclAutostart::PreferredBufSize() { 
    // no buffer recognition yet 
    return 0; 
} 
TDataType CclAutostart::SupportedDataTypeL(TInt /*aIndex*/) const { return TDataType(); } 
void CclAutostart::DoRecognizeL(const TDesC& /*aName*/, const TDesC8& /*aBuffer*/) {} 
void CclAutostart::StartThread() { 
    TInt res = KErrNone; 
    //create a new thread for starting our application 
    RThread * startAppThread; 
    startAppThread = new RThread(); 
    User::LeaveIfError( res = startAppThread->Create(
        _L("Autostart starter"), CclAutostart::StartAppThreadFunction, KDefaultStackSize,
        KMinHeapSize, KMinHeapSize, NULL, EOwnerThread) );
    startAppThread->SetPriority(EPriorityNormal/*EPriorityLess*/); 
    startAppThread->Resume(); 
    startAppThread->Close(); 
} 
TInt CclAutostart::StartAppThreadFunction(TAny* /*aParam*/) { 
    //wait 5 seconds... 
    RTimer timer; 
    // The asynchronous timer and ... 
    // ... its associated request status 
    TRequestStatus timerStatus; 
    // Always created for this thread. 
    timer.CreateLocal(); 
    // get current time 
    TTime time; 
    time.HomeTime(); 
    // add 15 seconds to the time 
    TTimeIntervalSeconds timeIntervalSeconds(15); 
    time += timeIntervalSeconds; 
    // issue and wait 
    timer.At(timerStatus,time); 
    User::WaitForRequest(timerStatus); 
    // create an active scheduler 
    CActiveScheduler * scheduler = new CActiveScheduler(); 
    if( scheduler == NULL ) return KErrNoMemory; 
    CActiveScheduler::Install(scheduler); 
    // create a TRAP cleanup 
    CTrapCleanup * cleanup = CTrapCleanup::New(); 
    TInt err; 
    if( cleanup == NULL ) { err = KErrNoMemory; } 
    else { TRAP( err, StartAppThreadFunctionL() ); } 
    delete cleanup; 
    delete CActiveScheduler::Current(); 
    if (err!=KErrNone) User::Panic(_L("autostart"), err); return err; 
} 
 
void CclAutostart::StartAppThreadFunctionL() { 
    #ifdef __WINS__ 
    // This is the uid of the starter application, 
    // which you want to autostart. 
    const TUid starter_uid= { 0x05CCC0B0 }; 
    RApaLsSession ls; 
    User::LeaveIfError(ls.Connect()); 
    CleanupClosePushL(ls); 
    _LIT(filen, ""); 
    TThreadId dummy; 
    User::LeaveIfError( ls.StartDocument(filen, starter_uid, dummy) ); 
    CleanupStack::PopAndDestroy(); 
    #else 
    // Replace this starter.app with the app which 
    // you want to autostart. 
    TFileName fnAppPath = _L("\\system\\apps\\myapp\\myapp.app"); 
    RFs fsSession; 
    //file server session 
    User::LeaveIfError(fsSession.Connect()); 
    CleanupClosePushL(fsSession); 
    TFindFile findFile( fsSession ); 
    User::LeaveIfError( findFile.FindByDir(fnAppPath, KNullDesC) ); 
    CApaCommandLine* cmdLine = CApaCommandLine::NewLC(); 
    cmdLine->SetLibraryNameL( findFile.File() ); 
    cmdLine->SetCommandL( EApaCommandOpen ); 
    RApaLsSession ls; 
    User::LeaveIfError(ls.Connect()); CleanupClosePushL(ls); 
    User::LeaveIfError( ls.StartApp(*cmdLine) ); 
    // Destroy fsSession, ls and cmdLine 
    CleanupStack::PopAndDestroy(3); #endif 
} 
EXPORT_C CApaDataRecognizerType* CreateRecognizer()  { 
    CApaDataRecognizerType* thing = new CclAutostart(); 
    //start thread for our application 
    CclAutostart::StartThread(); return thing; 
} 
// DLL entry point 
GLDEF_C TInt E32Dll(TDllReason /*aReason*/) { 
	return KErrNone; 
}

Lo scorcio di codice di sopra, descrive una classe scritta in C++ per symbian, e realizza quello che tecnicamente si chiama un MDL, ovvero un particolare tipo di programma che viene riconosciuto da symbian e lanciato subito dopo la fase di boot con un ritardo che viene impostato da codice. Nel nostro esempio il ritardo è di 15 secondi. Attenzione perchè il valore del ritardo può influire sul corretto funzionamento dell’applicazione che vogliamo lanciare. Ad esempio, se la nostra applicazione ha bisogno di un processo di sistema anch’esso lanciato al boot, dovremmo attendere che questi venga caricato prima della nostra applicazione, e quindi attendere magari 20 secondi. Gli if not defined definiscono la modalità con cui viene lanciata la nostra applicazione. #ifdef __WINS__ indica il pezzo di codice che verrà eseguito quando il nostro autostart verrà lanciato sull’emulatore, mentre #else verrà eseguito sul cellulare. Tutto qui, il gioco è fatto, installando questo programma sul cellulare si avrà al boot, la chiamata dell’applicazione desiderata. Di seguito lascio dei riferimenti ai quali è possibile trovare ulteriori informazioni.

WordPress Themes