Windows Mobile 6: Eseguire applicazioni in Suspended Mode

Com’è possibile immaginare esistono svariati contesti per i quali un’applicazione Smart Device ha la necessità di eseguire delle operazioni in Background. Sin qui nulla di nuovo…

Ma cosa accade in un dispositivo Windows Mobile nel momento in cui questo passa nella modalità Suspended? Per dirla in soldoni: cosa accade ad un processo quando il display del dispositivo si oscura definitivamente?

La risposta a questa domanda è davvero semplice: il processo passa allo stato “suspended”, in altre parole non viene eseguita nessuna riga di codice sino a che il device verrà risvegliato. Tale comportamento, viene stabilito da un componente del sistema chiamato Power Management.

Un semplice test che ci consente di verificare quanto scritto sopra, si può compiere tramite il seguente codice:

 public partial class Form1 : Form
{
    private Thread myThread;

    public Form1()
    {
        InitializeComponent();
        myThread = new Thread(toDo);
    }

    private void menuTest_Click(object sender, EventArgs e)
    {
        myThread.Start();
    }

    private void toDo()
    {
        using (StreamWriter log = new StreamWriter(@"\Foreground.txt"))
        {
            log.WriteLine("Test Started: " + DateTime.Now.ToLongTimeString());
            for (int i = 0; i < 30; i++)
            {
                if (i > 0)
                    Thread.Sleep(1000);
                log.WriteLine("Time: {0} i:{1}", DateTime.Now.ToLongTimeString(),
                    i.ToString());
            }
            log.WriteLine("Test Ended: " + DateTime.Now.ToLongTimeString());
        }
    }
}

Subito dopo aver lanciato l’applicazione e aver avviato il thread myThread, procediamo forzando il device ad andare in Suspended Mode (cliccando il power button). In seguito, ripristinando il dispositivo, otterremo il file Foreground.txt con un output simile al seguente

 Test Started: 6.49.03
Time: 6.49.03 i:0
Time: 6.49.04 i:1
Time: 6.49.05 i:2
Time: 6.49.06 i:3
Time: 6.49.07 i:4
Time: 6.49.09 i:5
Time: 6.49.10 i:6   // In questo istante il device è passato in Suspend Mode
Time: 6.49.31 i:7   // L'iterazione successiva avviene subito dopo aver risvegliato il dispositivo
Time: 6.49.32 i:8
Time: 6.49.33 i:9
Time: 6.49.34 i:10
Time: 6.49.35 i:11
Time: 6.49.36 i:12
Time: 6.49.37 i:13
Time: 6.49.38 i:14
Time: 6.49.39 i:15
Time: 6.49.40 i:16
Time: 6.49.41 i:17
Time: 6.49.42 i:18
Time: 6.49.43 i:19
Time: 6.49.44 i:20
Time: 6.49.45 i:21
Time: 6.49.46 i:22
Time: 6.49.47 i:23
Time: 6.49.48 i:24
Time: 6.49.49 i:25
Time: 6.49.50 i:26
Time: 6.49.51 i:27
Time: 6.49.52 i:28
Time: 6.49.53 i:29
Test Ended: 6.49.53

 

Come fare in modo che la nostra applicazione sia eseguita anche quando il device si trova in Suspended Mode?

A partire da Windows Mobile 6 è stato introdotto un nuovo stato in cui il dispositivo può essere settato programmaticamente: UNATTENDEDMODE, mediante API PowerPolicyNotify.

L’API di cui sopra consente al dispositivo di non passere nella modalità Suspend, (nella quale per definizione tutti i thread si fermano) ma in una speciale stato che consente alle applicazioni di eseguire operazioni in background. Il comportamento di tale stato è ben descritto qui:

“PPN_UNATTENDEDMODE is used only on Windows Mobile 6 Professional and Windows Mobile 6 Classic devices, but not on Windows Mobile 6 Standard or general embedded devices. Unattended mode tells the system that your code is running something that the user does not need to see, for example, synchronizing in the background. Call PowerPolicyNotify(PPN_UNATTENDEDMODE, TRUE) to get into unattended mode and PowerPolicyNotify(PPN_UNATTENDEDMODE, FALSE) to get out. This is a special state that is different than most. You can call it from any current state, but it only goes into that state in special cases. If the system is currently in Resuming state, it goes into the Unattended state. Otherwise, it stays in the current state and increments a reference count on Unattended. If the user presses the power button and the unattended reference count is greater than zero, the system goes into Unattended state, rather than Suspended state. Default levels are the same as for the On state. with the exception of LCD and audio, which are both in D4.”

Finita la parte teorica, passiamo ad un esempio pratico:

 public partial class Form1 : Form
{
    private Thread myThread;

    const int PPN_UNATTENDEDMODE = 0x00000003;

    public Form1()
    {
        InitializeComponent();
        myThread = new Thread(toDo);
    }
    
    
    private void menuTest_Click(object sender, EventArgs e)
    {
       // Inizia l'attività di background.
        myThread.Start();
    }

    private void toDo()
    {
        // Abilito la proprietà UNATTENDEDMODE per il DEVICE
        PowerPolicyNotify(PPN_UNATTENDEDMODE, 1);
        using (StreamWriter log = new StreamWriter(@"\Background.txt"))
        {
            log.WriteLine("Test Started: " + DateTime.Now.ToLongTimeString());
            for (int i = 0; i < 30; i++)
            {
                if (i > 0)
                    Thread.Sleep(1000);
                log.WriteLine("Time: {0} i:{1}", DateTime.Now.ToLongTimeString(),
                    i.ToString());
            }
            log.WriteLine("Test Ended: " + DateTime.Now.ToLongTimeString());                
            log.Dispose();              
        }
        // Disabilito la proprietà UNATTENDEDMODE per il device.
        PowerPolicyNotify(PPN_UNATTENDEDMODE, 0);
    }

    [DllImport("CoreDll.dll")]
    static extern bool PowerPolicyNotify(int dwMessage, int onOrOff);
}

E’ importante ricordare che la modalità UNATTENDEDMODE, avrà un ‘impatto su tutte le altre applicazioni che vengono eseguite sul dispositivo. Ad esempio, se eseguiamo l’ultima applicazione e contemporaneamente la prima mostrata, entrambe verranno eseguite in background anche se lo stato UNATTENDEDMODE è stato settato solamente da una delle due.