![](/themes/connect/images/creative-commons.png)
Quand on développe une application connectée, il faut garder à l'esprit que sur nos smartphones, la radio est le deuxième élément le plus consommateur de batterie juste derrière l'écran. Perché au sommet d'une pile d'APIs et de couches protocolaires, le développeur n'a pas toujours conscience de ce qu'il se passe sur l'interface radio de son mobile...
1. Introduction
1.1 Le contexte
La plupart des applications que nous utilisons sur nos terminaux mobiles sont connectées. Qu'il s'agisse de consulter la météo ou de tchater avec un ami, elles génèrent nécessairement du trafic réseau, je ne parle même pas des analytics tapis dans l'ombre. Il faut dire que c'est relativement « simple ». En tant que développeur, le framework Android (je me baserai dessus mais tout ce qui suit s'applique aussi aux autres OS mobiles) met à ma disposition une panoplie d'APIs qui me fournissent une couche d'abstraction afin que je n'ai pas à me soucier de ce qu'il se passe sous la coque dans mon appareil. Néanmoins, il me semble important de rappeler un certain nombre de mécanismes méconnus qui ont un rôle important dans la consommation de batterie.
1.2 Une question de point de vue
Vu du code source, le développeur travaille avec des APIs. Rien de très nouveau me direz vous. Seulement voilà ... une fois notre code source compilé, nous pourrons exécuter notre application et si elle doit établir des connexions vers des serveurs, elle sollicitera l'interface radio de notre mobile. À ce moment précis : une ribambelle de protocoles va entrer en jeu. Certains sont bien connus comme HTTP, TCP, IP, … d'autres un peu moins : RLC, PDCP et surtout RRC. La figure 1 rappelle la manière dont ces derniers s'empilent vu d'un logiciel sur PC, sur mobile et aussi vu du développeur.
Fig. 1: Empilement des API/protocoles vu du développeur et du terminal
Tout ceci reste relativement abstrait, mais si on ajoute dans la balance la batterie (elle, je peux la prendre en main et la sentir chauffer) on peut commencer à se poser les bonnes questions.
Une batterie de laptop peut fournir environ 85Wh, une batterie de smartphone « seulement » 5Wh. Par ailleurs, si mon PC portable est à plat au bout d'une ou deux heures, je peste mais d'une certaine manière je m'en accommode. S'il en allait de même pour mon smartphone, je serais beaucoup moins indulgent !
2. Que veut dire RRC ?
RRC signifie Radio Resources Control. Il s'agit d'une fonction primordiale du réseau mobile. Vous le savez, la ressource radio est quelque chose de limité et partagé. Il convient donc d'en optimiser l'usage. Les spécifications du 3GPP1 ont pour cela défini un composant dont le but est (entre autres) : l’établissement et la libération des canaux radio, ainsi que leur configuration.
Les protocoles TCP, IP, HTTP sont définis par l'IETF, le WiFi par l'IEEE, la 3G et la 4G par le 3GPP (3rd Generation Partnership Project). Ce projet produit une énorme quantité de spécifications qui couvre l'ensemble des fonctionnalités d'un réseau mobile, du téléphone (appelé User Equipment ou UE) jusqu'au cœur de réseau. À titre d'exemple, le document TS 25.331 définit le protocole RRC : 2000 pages, 80 références vers d'autres spécifications, voilà de quoi se faire une idée...
Dans le contexte de cet article, nous allons nous intéresser principalement à la machine d'état qu'il y a dernière. En 3G, elle comprend typiquement 4 états : IDLE, DCH, FACH, PCH. Ils reflètent la nature du canal radio utilisé et surtout, ils ont un impact non négligeable sur la batterie de notre smartphone.
- IDLE , aucun transfert réseau n'est possible. La radio est inactive la plupart du temps car le terminal ne se met en écoute que de temps en temps afin de savoir si le réseau le sollicite. La consommation est de ce fait très faible.
- DCH (Dedicated Channel), on dispose d'un canal dédié pour notre trafic réseau avec une bande passante élevée. Le prix à payer est que l'on consomme énormément de batterie (c'est bien beau de passer des paquets IP à votre chipset radio mais, à un moment, il faut moduler tout ça et l'émettre via l'antenne... ).
- FACH (Forward Access Channel), on passe par un canal partagé, le débit que l'on peut obtenir est très réduit comparé à l'état DCH et l'impact sur la batterie est environ moitié moindre.
- PCH (Paging Channel), à peu près similaire à l'état IDLE, on ne peut ni recevoir ni transmettre de données. Par contre, on reste dans un état dit « connecté » ce qui évite de relancer toute une procédure longue et coûteuse comme nous allons le voir dans le paragraphe suivant. En terme d'impact sur la batterie, c'est un peu moins négligeable que IDLE mais ça reste très faible.
La figure 2 illustre la machine d'état RRC.
Fig. 2: Machine d'état RRC.
Pourquoi s’encombrer d'un tel mécanisme ? Pour tenter de trouver un compromis entre trafic de signalisation, répartition des ressources et consommation d’énergie. Pas facile...
Le lecteur attentif peut ici se demander pourquoi ma transition PCH -> IDLE est en pointillé. L'expert quant à lui peut éventuellement s'en étonner. C'est principalement esthétique, le but étant d'avoir une machine d'état relativement simple à lire. En toute rigueur, lorsque l'on est en PCH, il faut d'abord repasser en FACH temporairement pour ensuite rejoindre l'état IDLE.
3. Qui déclenche les transitions ?
3.1 Le réseau ?
C'est l'approche initialement retenue par le 3GPP. Imaginons que je souhaite visualiser une page web sur mon mobile. Toute une procédure va se dérouler pour établir une liaison radio, demander une connexion RRC, configurer un canal pour le transfert de données, … des dizaines de messages divers et variés vont être échangés entre le terminal, le NodeB, le RNC et le SGSN (figure 3).
Fig. 3: Établissement d'une connexion « data » en 3G. Cela peut prendre jusqu'à 2 secondes.
À l'issue de ces échanges, le terminal sera dans l'état DCH et je pourrai télécharger ma page web. Pour la suite, on pourrait imaginer 2 scénarios :
- le terminal reste dans l'état DCH car il se peut que je clique sur un autre lien pendant ma lecture. J'ai donc potentiellement besoin de ce canal dédié. Par contre, je prends le risque de consommer inutilement de l'énergie et je réserve une ressource au détriment des autres utilisateurs,
- le terminal revient dans l'état IDLE car après tout il se peut que ma lecture s'arrête là, auquel cas il serait mieux de préserver ma batterie. Dans ce cas, si je clique sur un autre lien, il va falloir remonter le canal radio et reprendre la procédure longue et coûteuse décrite en figure 3.
Afin de trouver un juste milieu, le réseau va en fait demander au terminal de suivre ses recommandations. Une fois l'état DCH atteint, le réseau va attendre l'expiration d'un timer T1 (environ 5s) pour laisser au terminal une chance de réutiliser le canal dont il dispose. Si aucune activité n'a été rapportée, il va lui demander de passer dans l'état FACH. La batterie est ainsi soulagée et le canal dédié peut être attribué à quelqu'un d'autre. S'il fallait de nouveau faire des échanges de données, la transition vers l'état DCH serait très rapide car il suffit simplement de reconfigurer le canal existant. Enfin, s'il s'en suit une nouvelle période d'inactivité, déterminée par le timer T2 (environ 10s), le réseau demandera au terminal de passer directement dans l'état IDLE ou de passer dans l'état PCH quelques minutes (T3) avant de rejoindre l'état IDLE. D'une certaine manière, il joue avec un curseur : plus le niveau d’énergie est élevé plus les temps d'accès sont courts mais plus cela impacte la batterie. Les valeurs de ces timers sont données à titre d'exemple, elles sont configurables et peuvent donc varier d'un opérateur à l'autre.
Je pourrais m'arrêter là, mais j'en entends déjà certains demander : « quid du Fast Dormancy ?»
3.2 Le réseau et le terminal !
Dans un réseau mobile, il y a d'un coté : un réseau et de l'autre : des mobiles (c'est indiscutable...). Dans un monde idéal, les contraintes de l'un n'impactent pas les autres. Sauf que rien n'est jamais si simple. Du point de vue de l'infrastructure, il est important de limiter les échanges de signalisation (figure 3) pour une problématique de dimensionnement. Du point de vue du terminal mobile, il est important de pouvoir afficher une durée d'utilisation la plus longue possible. Comme évoqué plus haut, dans certains cas, il peut paraître opportun de passer de l'état DCH à l'état IDLE pour économiser la batterie. À l'origine, la norme a privilégié un modèle dans lequel le réseau avait la main pour décider des différentes transitions (que ce soit pour changer d'état ou même libérer la connexion). Néanmoins, il a été prévu qu'il soit possible pour un terminal d'indiquer au réseau qu'il a dû libérer sa connexion en envoyant un message SCRI (Signalling Connection Release Indication). Jusqu'à la release 7, quelle qu’en soit la motivation (typiquement lorsqu'un problème s'est produit), le terminal pouvait envoyer ce message et ensuite passer directement dans l'état IDLE. Évidemment, les fabricants de terminaux lisent soigneusement ces documents (bien qu'ils soient réputés être difficiles à digérer) et ont vu là un moyen de s'affranchir du dictât du réseau : « Nous allons envoyer un SCRI dès que notre téléphone ne fait plus de trafic réseau ». A priori, ça semble tenir la route comme stratégie. Après tout, on peut estimer que le terminal a une meilleure connaissance que le réseau du contexte dans lequel se font ces échanges. Mais dans la pratique, ce n'est pas si évident. D'une part, cela peut fortement impacter le réseau de l'opérateur car à chaque fois, il faudra établir une nouvelle connexion, ce qui entraîne une charge inutile de signalisation. D'autre part, l'expérience utilisateur sera dégradée car l'établissement du canal prend un certain temps : 2 secondes environ.
Il a donc fallu trouver un compromis pour satisfaire tout le monde. C'est ce qui est arrivé avec la release 8 des spécifications du 3GPP. Le message SCRI s'est enrichi d'une information relative à la cause d'abandon : « UE Requested PS Data session end » qui indique explicitement que le terminal n'a plus besoin du canal de signalisation. Lorsque cette cause est précisée, le terminal doit conserver sa connexion et donc rester à l'écoute des consignes du réseau. Typiquement, ce dernier lui indiquera alors de passer dans l'état PCH (lorsque le réseau le supporte). Tout le monde est gagnant, le terminal passe dans un état « dormant » qui consomme très peu de batterie, en cas de besoin la transition vers l'état DCH est beaucoup plus rapide car la connexion RRC n'a pas été coupée et le réseau reprend son pouvoir de décision. Si vous souhaitez approfondir ce sujet, la GSMA a produit un document très détaillé disponible sur le web : « Fast Dormancy Best Practices2 ».
Après ce petit court d'histoire relativement théorique, passons à la pratique. Dans les paragraphes qui suivent, nous allons illustrer ces quelques enseignements.
4. Travaux pratiques
Je vous propose dans cette partie de faire quelques travaux pratiques. Je m'appuierai sur 2 outils open source qui permettent de facilement « monitorer » un terminal sous Android : ATK et ARO.
ATK3 (Accelerator Test Kit) fournit 2 grandes fonctionnalités :
- mesures globales ou par application de la mémoire, la CPU, du trafic entrant/sortant,
- tests automatiques (enregistrement des actions depuis votre téléphone pour les rejouer)
ARO4 (Application Resources Optimizer) permet de diagnostiquer l'usage du réseau qui est fait par des applications mobiles.
Je dois reconnaître un certain parti pris dans le choix de ces outils car je suis actuellement le mainteneur du premier qui depuis peu intègre directement les fonctionnalités du second ;-) Ces 2 outils se complètent car ATK permet d'avoir une visualisation temps réel des mesures ainsi qu'une automatisation des tests tandis que ARO effectuera un traitement a posteriori afin de simuler la machine d'état RRC (et bien plus encore). J'insiste sur la notion de simulation. Actuellement, il n'existe pas d'API ouverte pour connaître l'état de la connexion RRC (mais cela pourrait changer prochainement5) . ARO se base donc sur des traces pcap prises sur le terminal avec tcpdump qu'il analyse et à partir desquels il infère la machine d'état.
4.1 Polling
Pour présenter des données à jour, le polling est une solution à moindres frais en terme de développement mais qui a un coût en terme de traitement (car cela sollicite des ressources du réseau, sur le serveur et sur le client de manière répétitive). Prenons un exemple simple : la lecture d'un flux RSS. Google en propose une implémentation ici : http://developer.android.com/training/basics/network-ops/xml.html. En bon développeur, je n'ai pas spécialement envie de réinventer la roue, ce morceau de code fera l'affaire. Je vais également demander à ATK de rafraîchir l'écran toutes les 10 minutes en simulant un utilisateur qui demande la mise à jour des données. Le trafic réseau ressemblera à ce qui est présenté figure 4. Si l'on s'en tient aux mesures effectuées par ATK, on ne peut que constater la périodicité du trafic - ce qui en soit est déjà intéressant.
StartMainlog(1000)
Sleep(10000)
Key(HOME)
TouchScreenPress(351, 1098, 45)
Sleep(1000)
TouchScreenPress(651, 1023, 64)
Loop(10)
Sleep(600000)
TouchScreenPress(688, 104, 65)
Sleep(500)
TouchScreenPress(583, 319, 94)
EndLoop
Sleep(5000)
Key(BACK)
StopMainlog
Fig. 4: Polling toutes les 10 minutes visualisé par ATK
Si l'on regarde à présent la figure 5 qui correspond à l'analyse que ARO a fait de notre session, on s'aperçoit qu'effectivement toutes les 10 minutes, il y a du trafic mais surtout que toutes les dix minutes, mon interface radio va consommer de la batterie pendant une vingtaine de secondes alors que le transfert n'a duré qu'un clin d'oeil... En fonction de l'application que vous testez, vous pouvez éventuellement être intéressés par le contenu des payloads, toutes ces informations sont accessibles facilement via les différents écrans de ARO. On peut par exemple voir ici que le serveur est stackoverflow.com, qu'on lui a envoyé un GET HTTP et que nous avons reçu un 200 OK.
Fig. 5: Polling toutes les 10 minutes visualisé par ARO
Si à présent, je remplace le Sleep(600000) par Sleep(20000) correspond à une période de 20 secondes, la simulation de ARO donnera les résultats présentés en figure 6. D'une manière assez claire, on s'aperçoit qu'à présent notre interface radio est quasiment tout le temps active. Voilà de quoi réfléchir à deux fois avant de diminuer la fréquence de rafraîchissement si vous souhaitez être informés dans de meilleurs délais qu’une news. Dans le même esprit, si vous souhaitez implémenter un mécanisme de keepalive dans votre application, dites-vous bien que chaque paquet que vous enverrez entraînera son jeu de transition et consommera de la batterie.
Fig. 6: Polling toutes les 20 secondes
4.2 Gestion des connexions
À force d’exécuter du code dans une JVM (je rappelle que je me base sur Android) ou reposant sur un framework qui peut dans certains cas pallier nos oublis, on peut avoir tendance à compter dessus systématiquement pour libérer nos ressources. Ça aide parfois mais cela peut également avoir des effets assez inattendus. Par exemple, si vous ne fermez pas explicitement une connexion HTTP, il y de grandes chances pour que ce soit en fait le serveur qui s'en charge à votre place. Comme HTTP s'appuie sur TCP, la fermeture d'un sens de communication se fait par l'émission d'un paquet FIN que le distant acquitte pour ensuite fermer son extrémité du canal en faisant de même (il y a plusieurs manières de terminer une connexion TCP, je vous laisse le soin de vous replonger dans la littérature pour tous les détails). Il n'y a pas de miracle, si le serveur décide de fermer la connexion alors que le terminal est dans l'état IDLE, le terminal va devoir à nouveau établir un canal radio sur lequel passera la signalisation TCP et nous voilà repartis pour les échanges décrits plus haut et le passage par les différents états RRC. En d'autres termes, un gaspillage d'énergie comme l'illustre la figure 7.
Fig. 7: Connexion fermée à l'initiative du serveur
4.3 Répartition du trafic
Supposons que vous avez développé une application qui permet d'écouter de la musique en ligne. Afin de préparer la future version, vous vous dites qu'il serait bon de disposer de données sur l'usage qui en est fait : combien de titres sont consultés avant qu'un morceau ne soit effectivement joué, ou ce genre d'informations,... Dans la trace présentée en figure 8, on observe deux catégories de trafic :
- un trafic périodique en rose qui correspond à la remontée des informations d'usage vers un serveur (le débit est extrêmement faible et quasiment invisible sur le graphe),
- un trafic dense en gris correspondant au streaming d'un extrait de musique (cette fois, on constate clairement un pic de débit en rouge).
Fig. 8: Trace d'une application de streaming audio
Au-delà de cette représentation graphique, ARO propose une large gamme de statistiques dont la plus intéressante dans ce cas précis est la « Burst Analysis » (figure 9).
Fig. 9: Burst Analysis
J'ai volontairement omis de mettre en évidence les informations importantes pour vous laisser une chance de les découvrir par vous même.
Conclusion
Depuis quelques années, le développement d'applications dédiées aux mobiles s'est énormément démocratisé et c'est une excellente chose. Si les composants logiciels (OS, frameworks, librairies) peuvent « aisément » évoluer au grès des usages, il n'en va pas forcément de même pour l'infrastructure sous-jacente. Cette dernière a quand même connu son lot d'améliorations, par exemple, les débits atteignables ont énormément progressé grâce successivement au HSDPA, HSUPA, HSPA, et HSPA+. Pour autant, certains mécanismes décrits dans cet article ont été définis il y a plus de 10 ans à une époque où nos usages n'avaient pas grand-chose à voir avec ce que l'on a l'habitude de faire aujourd'hui et n'ont que peu évolué. L'architecture d'un réseau mobile est complexe, certaines parties peuvent évoluer plus facilement que d'autres. Vous vous êtes peut-être parfois demandé pourquoi telle ou telle application épuisait votre batterie rapidement, vous avez à présent quelques pistes. Ce ne sont bien entendu pas les seules. Néanmoins, il reste important de bien considérer ces aspects lorsqu'on développe une application mobile. Le titre précisait « en 3G » pour une raison simple : avec l'arrivée de la 4G, la machine d'état RRC a été révisée : il n'y a plus que 2 états. Ce sera peut-être l'objet d'un prochain article.
Pour ceux qui n'ont pas pris le temps de jeter un œil sur la figure 8 tout à l'heure, regardez les colonnes 3 et 5 des lignes 2 et 4. Les 0,2% du trafic correspondant à la remontée d'usages ont consommé 65% de l’énergie alors que les 99,7% de trafic utile en ont consommé 16,8%.
Références
2 http://www.gsma.com/newsroom/wp-content/uploads/2013/08/TS18v1-0.pdf
3 https://github.com/Orange-OpenSource/ATK
4 http://developer.att.com/application-resource-optimizer
5 https://android-review.googlesource.com/#/c/49064/