Esta página corresponde a um capítulo retirado diretamente de um trabalho de conclusão de curso, de engenharia de software da Universidade de Brasília, que descreve alguns aspectos do sistema Android e a engenharia de software aplicada a ele. Para ler o trabalho completo, clique aqui.

Sistema Operacional Android

editar

Descrição Geral

editar

O Android é um sistema operacional para dispositivos móveis com base em kernel linux modificado, com várias bibliotecas modificadas ou refeitas, de forma a deixar o sistema tão eficiente quanto possível para o hardware limitado que os dispositivos alvo apresentam. A exemplo disso está a biblioteca C Bionic, que foi desenvolvida para menor consumo de espaço físico, memória e poder de processamento que as bibliotecas padrão C como a GNU C (glibc) (DEVOS, 2014). Aplicações desenvolvidas para Android são feitas essencialmente em linguagem Java, com a possibilidade de utilizar outras linguagens como C e C++ através da Java native interface (JNI).

O sistema Android tira vantagem do kernel linux no que diz respeito a identificação e separação de processos rodando no sistema, atribuindo a cada aplicação um UID (User Identification), e executando cada uma em um processo diferente, isolando umas das outras. Independentemente de a aplicação ser desenvolvida em Java ou com código nativo, essa separação de processos do kernel, conhecida como Application Sandbox, garante que a aplicação está isolada das demais e portanto sujeita aos mesmos mecanismos de segurança inclusive que os aplicativos do sistema, como contatos, câmera, entre outros.

Nas versões anteriores ao Lollipop, cada uma dessas aplicações no sistema funcionava em uma instância diferente da Dalvik Virtual Machine (DVM), enquanto atualmente a DVM foi substituída pela Android Run Time (ART), introduzida opcionalmente desde a versão kitkat. Ambas são máquinas virtuais semelhantes a Java Virtual Machine (JVM). Códigos em Java são compilados e traduzidos para formato .dex (dalvik executable), que é executado pela DVM, semelhante ao formato .jar do Java. Enquanto a DVM utiliza just-in-time compilation, compilando trechos do código para execução nativa em tempo de execução, a nova ART introduz o Ahead-of-time compilation, realizando compilações em tempo de instalação. Embora a instalação possa levar mais tempo dessa forma, essa mudança permite que os aplicativos tenham maior performance em sua execução. Esse isolamento de aplicativos, onde cada um é executado em sua própria instancia da máquina virtual, permite que uma falha em um processo de uma aplicação não tenha impacto algum em outra aplicação.

Para interagir com determinados serviços do sistema bem como outras aplicações, uma aplicação deve ter os privilégios correspondentes a ação que deseja executar. Por exemplo, o desenvolvedor pode solicitar ao sistema que sua aplicação tenha acesso a internet, privilégio não concedido por padrão pelo sistema. O usuário então no momento da instalação dessa aplicação é informado que a mesma deseja acesso a internet, e ele deve permitir acesso se quiser concluir a instalação. Todas as permissões requisitadas pelo desenvolvedor e necessárias para o aplicativo realizar suas funções são listadas no momento de instalação, e todas devem ser aceitas, caso contrário a instalação é cancelada. Não é permitido ao usuário selecionar quais permissões ele quer conceder e quais rejeitar à aplicação sendo instalada, tendo apenas as opções de aceitar todas elas, ou rejeitar a instalação.

O Android procura ser o mais seguro e facilmente utilizado sistema móvel, modificando a forma que várias tarefas são executadas para alcançar esse objetivo, como por exemplo fazer o isolamento de aplicações utilizando a separação de processos e usuários do kernel linux para gerenciar aplicativos instalados e proteger os dados dos mesmos. Aplicativos devem ser assinados e obrigatoriamente isolados uns dos outros (incluindo aplicativos do sistema) e devem possuir permissões explícitas para acessar recursos do sistema e outros aplicativos. As decisões arquiteturais relacionadas a segurança foram tomadas desde o início do ciclo de desenvolvimento do sistema, e continuam sendo prioridade.

Todo o código do sistema, incluindo a bionic, a Dalvik Virtual Machine e Android Run Time, é aberto para contribuição de qualquer desenvolvedor. Através do Android Open Sorce Project (AOSP), as fabricantes de dispositivos obtém o código do sistema, modificam conforme desejarem, adicionam aplicativos próprios e distribuem com seus produtos.

Estrutura de uma aplicação

editar

Aplicações no Android são construídas a partir de quatro tipos de componentes principais: Activities, Services, Broadcast Receivers, e Content Providers (HEUSER et al., 2014).

  • Uma Activity é basicamente o código para uma tarefa bem específica a ser realizada pelo usuário, e apresenta uma interface gráfica(Graphic User Interface) para a realização dessa tarefa.
  • Services são tarefas que são executadas em background, sem interação com o usuário. Services podem funcionar no processo principal de uma aplicação ou no seu próprio processo. Um bom exemplo de services são os tocadores de músicas. Mesmo que sua interface gráfica não esteja mais visível, é esperado que a música continue a tocar, mesmo se o usuário estiver interagindo com outro aplicativo.
  • Broadcast Receiver é um componente que é chamado quando um Intent é criado e enviado via broadcast por alguma aplicação ou pelo sistema. Intents são mecanismos para comunicação entre processos, podendo informar algum evento, ou transmitir dados de um para o outro. Um aplicativo pode receber um Intent criado por outro aplicativo, ou mesmo receber intents do próprio sistema, como por exemplo informação

de que a bateria está fraca ou de que uma busca por dispositivos bluetooth previamente requisitada foi concluída.

  • Content providers são componentes que gerenciam o acesso a um conjunto de dados. São utilizados para criar um ponto de acesso a determinada informação para outras aplicações. Para os contatos do sistema, por exemplo, existe um Content Provider responsável por gerenciar leitura e escrita desses contatos.

Cada um desses componentes pode funcionar independente dos demais. O sistema Android foi desenvolvido dessa forma para que uma tarefa mais complexa seja concluída com a ajuda e interação de vários desses componentes independente da aplicação a qual eles pertencem, não necessitando que um desenvolvedor crie mecanismos para todas as etapas de uma atividade mais longa do usuário.

Para executar a tarefa de ler um email, por exemplo, um usuário instala um aplicativo de gerenciamento de emails. Então ele deseja abrir um anexo de um email que está em formato PDF. O aplicativo de email não precisa necessariamente prover um leitor de PDF para que o usuário consiga ter acesso a esse anexo. Ele pode mandar ao sistema a intenção de abrir um arquivo PDF a partir de um Intent, e então o sistema encontra um outro componente que pode fazer isso, e o instancia. Caso mais de um seja encontrado, o sistema pergunta para o usuário qual é o componente que ele deseja utilizar. O sistema então invoca uma Activity de um outro aplicativo para abrir esse arquivo. Continuando no mesmo exemplo, o usuário clica em um link dentro do arquivo pdf. Esse aplicativo, por sua vez, pode enviar ao sistema a intenção de abrir um endereço web, que mais uma vez encontra um aplicativo capaz de o fazer.

É importante perceber que para uma atividade mais complexa de interação com o usuário, vários aplicativos são envolvidos sem que os mesmos tenham conhecimento dos demais. Cada componente se “registra” no sistema para realizar determinada tarefa, e o sistema se encarrega de encontrar os componentes adequados para cada situação. Esse registro dos componentes é realizado através do AndroidManifest.xml, que é um arquivo incluso em toda aplicação sendo instalada. Ele reúne todos os componentes de uma aplicação, as permissões necessárias para acessar cada um deles, e as permissões que eles utilizam, bem como outras informações.

Uma vez que os componentes de uma aplicação podem ser utilizados por outras aplicações, é necessário um controle maior sobre quem pode ter acesso a cada um deles. Cada desenvolvedor pode criar permissões customizadas para seus componentes, e exigir que o aplicativo que requisite a tarefa tenha essa permissão para acessar o componente. Da mesma forma, o aplicativo que criou essa permissão determina os critérios para conceder a mesma para outros aplicativos. Um simples exemplo de uso desse mecanismo é o fato de uma empresa apenas criar vários aplicativos para tarefas distintas e querer integração entre os mesmos. O desenvolvedor pode definir uma permissão específica para acessar um dos seus Content Providers, por exemplo, e definir que apenas aplicativos com a mesma assinatura (assinados pelo mesmo desenvolvedor) possam receber essa permissão. Dessa forma, todos os aplicativos desenvolvidos por essa empresa podem ter acesso aos dados gerenciados por esse Content Provider, enquanto as demais aplicações não tem esse acesso. Aplicativos pré instalados ou internos do sistema podem conter um tipo de permissão específica que só é dada a aplicativos do sistema, e não pode ser obtida por nenhum outro aplicativo instalado pelo usuário.

Diversidade e Compatibilidade

editar

O Android foi projetado para executar em uma imensa variedade de dispositivos, de telefones a tablets e televisões. Isso é muito interessante no ponto de vista do desenvolvedor, que tem como mercado para seu software usuários de diversos dispositivos de diversas marcas diferentes. Entretanto, isso trás uma necessidade de fazer uma interface flexível, que permita que um aplicativo seja utilizável em vários tipos de dispositivos, com vários tamanhos de tela. Para facilitar esse problema, o Android oferece um framework em que se pode prover recursos gráficos distintos e específicos para cada configuração de tela, publicando então um aplicativo apenas que se apresenta de forma diferente dependendo do dispositivo onde ele está sendo executado.

A interface gráfica no Android é essencialmente construída em XML, e tem um padrão de navegação para as aplicações, embora fique a critério do desenvolvedor a aparência de sua aplicação. O desenvolvedor por criar, por exemplo, uma interface gráfica com arquivos XML para cada tamanho de tela, e também diferenciar entre modo paisagem e modo retrato. Entretanto, em se tratando de interface gráfica, vários componentes vão sendo adicionados a API Android ao longo de sua evolução, e portanto vários recursos gráficos necessitam de uma versão mínima do sistema para serem utilizados. Utilizar um recurso presente apenas a partir da versão ICS 4.0.4 (Ice Cream Sandwich), por exemplo, implica que o aplicativo não tenha compatibilidade com versões anteriores do sistema.

Da mesma forma, devido a diversa variedade de modelos e fabricantes de hardware, é preciso ficar atento aos recursos de hardware disponíveis para cada dispositivo. Alguns sensores hoje mais comuns aos novos dispositivos sendo lançados no mercado não existiam em modelos mais antigos. O desenvolvedor pode especificar no Android manifest os recursos necessários para o funcionamento completo de sua aplicação, de forma que a mesma seja apenas instalada em dispositivos que os apresentarem. Também pode ser feita uma checagem em tempo de execução e apenas desativar uma funcionalidade do aplicativo caso algum recurso de hardware não esteja disponível no dispositivo, se isso for o desejo do desenvolvedor. De forma geral, é relativamente simples a forma com que o desenvolvedor especifica os dispositivos alvo para sua aplicação, tornando essa grande diversidade de dispositivos mais vantajosa do que dispendiosa.

Android é um sistema livre, que pode ser utilizado em modificado e utilizado segundo a licença Apache versão 2.2. Shanker e Lal (2011) apresenta alguns tópicos relacionados a portabilidade do sistema Android em um novo hardware. Embora não seja discutida nesse documento, a relativamente fácil portabilidade do sistema para vários tipos de hardware foi uma das razões que levaram seu rápido crescimento, fazendo com que várias fabricantes possam fazer uso do mesmo sistema e lançar vários tipos de dispositivos distintos no mercado, com diferentes features e preços, alcançando parcelas do mercado que possuem condições de aquisição muito variadas.

Engenharia de Software aplicada ao Android

editar

Engenharia de software é definida pela (IEEE, 2014) como aplicação de uma abordagem sistemática, disciplinada e mensurável ao desenvolvimento, operação e manutenção de software. As subseções desta seção citam alguns dos processos da engenharia de software que são importantes em todo o ciclo de vida do produto de software, que inclui desde a concepção do produto até a manutenção do mesmo em ambiente de produção, no contexto de plataformas móveis, e em específico, no Android.

Seleção de plataformas móveis

editar

Holzer e Ondrus (2009) Por exemplo, propõe 3 critérios para seleção de plataformas móveis no ponto de vista do desenvolvedor:

  • Remuneração - Relacionado ao número de potenciais clientes que podem adquirir o produto. Plataforma com grande número de usuários e crescimento constante é de grande valia para desenvolvedores. Um ponto centralizado de venda de aplicativos também é um atrativo para a comercialização dos softwares desenvolvidos.
  • Carreira - As oportunidades que o desenvolvimento para a plataforma pode gerar. A possibilidade de trabalhar para grandes e renomadas empresas no mercado pode ser um fator decisivo para a escolha da plataforma. Para aumentar sua credibilidade na comunidade de desenvolvedores e ganhar visibilidade no mercado, Holzer e Ondrus (2009) sugere que o desenvolvedor participe de projetos de software livre, o que é facilitado quando a própria plataforma móvel é aberta.
  • Liberdade - Liberdade criativa para desenvolver. O programador deve sentir que na plataforma ele pode programar o que quiser. Uma plataforma consolidada com excelentes kits de desenvolvimento e dispositivos atrativos do ponto de vista de hardware e sistema operacional atraem muitos desenvolvedores. Plataformas fechadas e com muitas restrições tendem a afastar desenvolvedores que querem essa liberdade,

enquanto plataformas abertas apresentam maior liberdade para desenvolvimento.

Com seu grande crescimento e consequente tomada da maior fatia do mercado de dispositivos móveis, a plataforma Android consegue ser bastante atrativa no ponto de vista primeiro tópico, em contraste com as demais plataformas do mercado, como WindowsPhone e iOS. Mais e mais empresas aparecem no contexto do Android tanto em desenvolvimento de hardware quanto software, e as oportunidades de trabalho crescem juntamente com o crescimento da própria plataforma, como sugerido no segundo tópico. Por ser aberto, a plataforma Android também permite que desenvolvedores enviem suas contribuições e correções de bugs ao próprio sistema operacional, aumentando sua visibilidade. Da mesma forma, o Android também apresenta um sistema totalmente aberto e com kits de desenvolvimento consolidados e extensiva documentação disponível online, no mínimo se equiparando ao seu principal concorrente iOS em liberdade de desenvolvimento na data de escrita desse documento.

Segundo Wasserman (2010), alguns aspectos devem ser pensados quando desenvolvendo software para dispositivos móveis:

  • Requisitos de interação com outras aplicações;
  • Manipulação de sensores;
  • Requisitos web que resultam em aplicações hibridas (mobile - web);
  • Diferentes famílias de hardware;
  • Requisitos de segurança contra aplicações mal intencionadas que comprometem o uso do sistema;
  • Interface de Usuário projetadas para funcionar com diversas formas de interação e seguir padrões de design da plataforma;
  • Teste de aplicações móveis são em geral mais desafiadores pois são realizados de maneira diferente da maneira tradicional;
  • Consumo de energia;

Todos esses tópicos mencionados são muito importantes para o desenvolvimento em várias plataformas móveis, e modificam a forma com que várias atividades da engenharia de software devem ser abordadas. A plataforma Android tem sua arquitetura projetada para atender a vários desses quesitos:

  • As aplicações são isoladas e se comunicam de forma unificada com outras aplicações ou com componentes e recursos do sistema;
  • A linguagem Java de programação da uma imensa liberdade de utilizar diversas bibliotecas e frameworks desenvolvidos anteriormente para o Java;
  • A camada de máquina virtual correspondente a DVM e ART permite uma abstração do uso dos componentes físicos e aumenta assim a compatibilidade com diversos tipos e famílias de hardware;
  • A segurança foi prioridade desde os primeiros estágios de desenvolvimento, tentando prever inclusive ataques de engenharia social que tentam convencer o usuário a instalar aplicações maliciosas em seu dispositivo;
  • A interface de usuário dos aplicativos é extremamente customizável, ainda podendo manter facilmente um padrão de navegação;
  • Testes no sistema foram projetados para cada componente isoladamente, tentando facilitar o processo de teste de aplicativos;
  • Recursos do sistema tem controle minucioso para melhor gerenciamento de uso de energia.

Tomando os critérios apresentados como base, a escolha da plataforma Android para desenvolvimento neste trabalho é feita de forma clara.

Requisitos

editar

Área de conhecimento em requisitos de software é responsável pela elicitação, análise, especificação e validação de requisitos de software, bem como a manutenção gerenciamento desses requisitos durante todo o ciclo de vida do produto (IEEE, 2014).

Requisitos de software representam as necessidades de um produto, condições que ele deve cumprir para resolver um problema do mundo real que o software pretende atacar. Essas necessidades podem ser funcionalidades que o software deve apresentar para o usuário, chamados requisitos funcionais, ou outras condições que restringem as funcionalidades de alguma forma, seja por exemplo sobre tempo de execução, requisitos de segurança ou outras restrições, conhecidas como requisitos não funcionais.

Requisitos não funcionais são críticos para aplicações móveis, e estas podem precisar se adaptar dinamicamente para prover funcionalidade reduzida (DEHLINGER; DIXON, 2011). Embora o hardware de dispositivos móveis tenha avançado bastante nos últimos anos, dispositivos móveis ainda apresentam capacidade reduzida de processamento devido a limitações como o tamanho reduzido e capacidade limitada de refrigeração. Devido a essas e outras limitações e a grande variedade de dispositivos Android no mercado, com poder computacional bem variado, aplicativos devem ser projetados para funcionar em hardware limitado. Em suma, deve-se pensar sempre em requisitos de performance e baixo consumo de recursos: uso de rede (3g/4g/wifi/bluetooth...), energia, ciclos de processamento, memória, entre outros. Wasserman (2010) afirma que o sucesso de qualquer aplicação, mobile ou não, depende de uma grande lista de requisitos não funcionais.

Segundo Dehlinger e Dixon (2011), deve-se analisar bem requisitos de contexto de execução de aplicativos dispositivos móveis. Aplicações móveis apresentam contextos de execução que não eram obtidos em tecnologias anteriores, com dados adicionais como localização, proximidade a outros dispositivos, entre outros, que podem alterar a forma com que os aplicativos são utilizados. Aplicativos móveis tem que ser pensados para se adaptar com essas mudanças de contexto.

O sistema Android permite checar a disponibilidade de recursos de hardware em tempo de instalação ou execução para que o desenvolvedor possa ajustar as funcionalidades apresentadas ao usuário e prevenir que o usuário encontre problemas na utilização de determinadas funcionalidades. Por exemplo, um jogo simples como um tic tac toe que utilize bluetooth para multiplayer pode desativar essa funcionalidade para dispositivos antigos que o não tenham disponível e trabalhar apenas com jogo single player contra algum tipo de jogador virtual. Da mesma forma, a ausência de algum recurso pode impedir que algum aplicativo seja instalado no dispositivo. O whatsapp, por exemplo, não pode ser instalado em dispositivos que não possuem comunicação com rede móvel via cartão SIM, como tablets que possuem apenas comunicação WIFI. Dessa forma é possível prevenir a apresentação para o usuário de funcionalidades que ele na verdade não pode executar.

Requisitos de software podem ser representados de diversas formas, sendo possível a utilização de vários modelos distintos. Na metodologia ágil scrum, por exemplo, os requisitos normalmente são registrados na forma de User Stories, onde são geralmente descritos na visão do usuário do sistema. Em outros contextos, podem ser descritos em casos de uso, com descrições textuais e diagramas, ou outras várias formas de representação.

Requisitos de software geralmente tem como fonte o próprio cliente que contrata o serviço do desenvolvimento de software, e são extraídos da descrição de como esse cliente vê o uso do sistema. Todo esse processo é muitas vezes chamado de “engenharia de requisitos”.

Essa diferenciação que pode ser observada em requisitos para plataformas móveis em relação a software convencional também é refletida nas outras fases de desenvolvimento. Um produto idealizado de forma diferente acarreta em um produto trabalhado totalmente de forma diferente. As possíveis interações entre usuário e sistema, ou entre usuários, dão novos contextos de utilização para o produto de software. A forma como os usuários utilizam o próprio sistema alvo do software sendo desenvolvido muda a forma com que atividades de criação e inovação, planejamento, desenvolvimento, implantação e até mesmo distribuição e marketing são conduzidas.

Desenho

editar

Desenho de software é o processo de definição da arquitetura, componentes, interfaces, e outras características de um sistema ou um componente (IEEE, 2014). É durante o desenho de software que os requisitos são traduzidos na estrutura que dará base ao software sendo desenvolvido. As necessidades então são traduzidas em modelos, que descrevem os componentes e as interfaces entre os componentes. A partir desses modelos é possível avaliar a validade da solução desenhada e as restrições associadas a mesma, sendo possível avaliar diferentes soluções antes da implementação do software. A partir do design da arquitetura, é possível prever se alguns requisitos elicitados podem ou não ser atingidos com determinada solução, e mudá-la conforme necessário com pouco ou mesmo nenhum custo adicional.

A área de desenho de software pode variar conforme a tecnologia sendo utilizada. A arquitetura do sistema pode variar conforme o sistema operacional alvo, ou mesmo conforme a linguagem de programação que se está utilizando no desenvolvimento. Existem vários princípios de design de software amplamente conhecidos que se aplicam a uma imensidade de situações, sempre com o intuito de encontrar a melhor solução para cada situação e deixar o software modularizado e manutenível.

Aplicativos para o sistema Android são construídos em módulos, utilizando os componentes da API, embora possam ser criadas classes em Java puro sem a utilização de nenhum recurso da API do sistema, e utilizá-las nos componentes assim como em uma aplicação Java padrão desenvolvida para desktop. Várias classes de modelo em uma arquitetura MVC (Model-View-Controller), por exemplo, possivelmente serão criadas em Java puro. Por outro lado, o Android não impõe nenhuma arquitetura específica no desenvolvimento de aplicações, deixando livre para o desenvolvedor fazer suas escolhas.

Sokolova, Lemercier e Garcia (2013) apresentam alguns tipos de arquitetura derivados do bem difundido MVC, e demonstram uma possibilidade de adaptação do MVC ao Android. Embora a arquitetura MVC possa ser utilizada no Android, ela não é facilmente identificada, e não é intuitiva de ser implementada. Activities são os componentes mais difíceis de serem encaixados na arquitetura MVC padrão, embora sejam bem adaptadas às necessidades do desenvolvedor. Por padrão elas tem responsabilidades correspondentes ao Controller e ao View, e são interpretadas de forma diferente por vários desenvolvedores para o MVC.

O Android provê um framework para desenvolver aplicativos baseado nos componentes descritos no início dessa página. Os aplicativos são construídos com qualquer combinação desses componentes, que podem ser utilizados individualmente, sem a presença dos demais. Cada um dos componentes pode ser uma entrada para o aplicativo sendo desenvolvido.

A comunicação direta entre os componentes de cada aplicativo é feita por meio do Binder, mecanismo de comunicação entre processos. O Binder comunica processos através da troca de mensagens (chamadas parcels), que podem referenciar dados primitivos e objetos da API assim como referencias para outros objetos binder. De forma geral, um service no Android pode ter sua interface definida em AIDL (Android Interface Definition Language), e uma aplicação que tiver referencia para o binder desse service pode executar chamadas de procedimento remoto (RPC - remote procedure calls) para qualquer método definido nessa interface AIDL de forma síncrona. Embora o binder apresente acesso direto para alguns componentes, essa comunicação pode ser feita de forma indireta utilizando Intents. Intents são geralmente recebidos por receivers que estão registrados para recebê-los. Esse registro é feito por meio de Intent Filters. Entretanto, activities e services também podem utilizar desse mecanismo para ser iniciados e finalizados. Quando um Intent é enviado ao sistema via broadcast, ele é recebido pelo sistema e resolvido pelo Activity Manager Service (AMS), que seleciona o melhor componente para tratá-lo, e então inicia o componente que o recebeu independente da aplicação a que ele pertença. Assim como já descrito, permissões podem ser criadas para restringir essa comunicação, mas a principio qualquer componente pode receber um intent de qualquer outra. Embora essas formas de comunicação entre processos sejam recomendadas, o sistema Android também suporta mecanismos de comunicação padrões do Linux como sockets e pipes (HEUSER et al., 2014).

Ainda que os componentes sejam geralmente registrados no sistema através do AndroidManifest.xml, BroadcastReceivers podem ser registrados dinamicamente dentro do ciclo de vida da aplicação. Isso quer dizer que é possível criar um receiver projetado para funcionar apenas enquanto a aplicação estiver em execução. Esse BroadcastReceiver então é registrado por linha de comando da API e desativado quando requisitado, criando uma janela de tempo onde se deseja que esse componente funcione.

De forma geral, para desenhar uma arquitetura para sistema Android deve-se levar em conta todos esses componentes e conhecer bem sua aplicabilidade e a comunicação entre os mesmos. Se for necessário ter algum processo em background independente de feedback do usuário, por exemplo, deve-se utilizar do componente service. Caso contrário, quando o usuário fechar a interface gráfica do aplicativo, o aplicativo terá sua execução pausada e seu estado salvo para retorno posterior, deixando de executar alguma tarefa que não deveria ter sido interrompida. Como um exemplo mais palpável, o aplicativo do facebook precisa necessariamente utilizar de um service para que, mesmo quando não estiver em foco no sistema, notificações de mensagens e atualizações de status cheguem na tela do usuário.

Embora pareça restringir o design de aplicativos, o uso desses componentes unifica a forma com que os aplicativos são desenvolvidos. A API do Android já disponibiliza acesso a vários recursos de hardware do sistema na forma de componentes, e assim como é possível utilizar os componentes do sistema, é possível utilizar componentes de qualquer outra aplicação da mesma maneira - se a permissão for concedida- , e criar os seus próprios componentes para uso de terceiros de forma padronizada. Em suma, é tão fácil usar componentes criados por alguma aplicação qualquer quanto componentes internos do sistema graças ao framework de desenvolvimento Android.

Interface de usuário
editar

O design de interface deve ser realizado com o intuito de alcançar usuários com capacidades motoras restritas, e outras limitações como problemas de visão ou audição. Dependendo do público alvo do aplicativo, esses aspectos devem ser considerados.

Com o desafio de fazer uso do pequeno espaço de tela, o design da interface gráfica apresenta mais importância do que jamais teve no desenvolvimento de aplicativos móveis (WASSERMAN, 2010). Usuários estão sempre tentando acessar várias tarefas diferentes, e geralmente tem baixa tolerância a aplicativos instáveis ou não responsivos, mesmo que gratuitos (DEHLINGER; DIXON, 2011).

A base da interface gráfica de usuário no Android é construída em cima da classe View, sendo que todos os elementos visíveis na tela, e alguns não visíveis, são derivados dessa classe (BRAHLER, 2010). O sistema Android disponibiliza vários componentes gráficos como botões, caixas de texto, imagens, caixas de seleção de dados, calendário, componentes de mídia (áudio e vídeo), entre outros, e a interface gráfica é construída em cima desses componentes gráficos, que podem ser customizados para um comportamento ou aparência um pouco diferente se assim for desejado, estendendo e customizando suas respectivas classes em Java. Existe um padrão de design que é recomendado que seja seguido.

A interface gráfica do usuário é construída geralmente em formato XML utilizando esses componentes gráficos já disponibilizados na API. Esses arquivos XML são então carregados pela API em Java quando necessário, e podem ser editados dinamicamente através da API, em linguagem Java.

Todo projeto de aplicativo Android possui um arquivo em Java chamado R (Resources) autogerado que contém identificação dos recursos do aplicativo. Cada componente gráfico disponibilizado na API e utilizado nos arquivos XML pode ser identificado de qualquer local do aplicativo pelo seu ID atribuído no arquivo XML. Dessa forma, é possível localizar facilmente dentro de sua Activity cada componente para ser carregado, modificado e utilizado.

Construção

editar

Essa área de conhecimento é responsável pela codificação do software, por transformar a arquitetura desenhada e seus modelos em código fonte. A construção de software está extremamente ligada ao desenho e às atividades de teste, partindo do primeiro e gerando insumo para o segundo (IEEE, 2014).

Várias medidas podem ser coletadas do próprio código pra auxiliar a avaliação da qualidade do produto sendo construído e gerar insumo para o próprio desenvolvedor reavaliar sua implementação antes da fase de testes.

Este trabalho visa auxiliar a fase de construção de aplicativos Android através da análise de métricas estáticas de código que refletem o design nesse contexto de desenvolvimento Android. O objetivo dessa análise é auxiliar desenvolvedores de aplicativos nos primeiros estágios de desenvolvimento e continuamente durante a construção do produto, provendo uma avaliação do estado atual e uma base de comparação para o projeto durante todo o ciclo de vida, trabalhada a partir do código do sistema e de aplicativos nativos, como email, calendário, contatos, câmera, calculadora e o web browser.

Essa base de comparação deve ser idealizada como uma referência válida para este contexto de desenvolvimento de aplicativos, então as conclusões tiradas para o código do sistema devem se mostrar válidas também para aplicativos desenvolvidos para o mesmo. O acoplamento de aplicativos com a própria API do sistema indica que isso é uma possibilidade bastante plausível.

Para construção de aplicativos para a plataforma Android, o Google disponibiliza um kit de desenvolvimento de aplicativos chamado Android SDK (Software Development Kit). Ele provê as bibliotecas da API e as ferramentas necessárias para construir, testar e debugar aplicativos. Android SDK está disponível para os sistemas operacionais Linux, MAC e Windows.

A ferramenta oficial para desenvolvimento de aplicativos Android é o Android Studio. O Android SDK atualmente é baixado instalado juntamente com o instalador do Android Studio. O IDE Eclipse ainda pode ser utilizado para desenvolvimento juntamente com plugin ADT (Android Development Tools), que inclui as ferramentas de visualização de interface em XML, ferramentas de debug de código, de análise de arquitetura, níveis de hierarquia de componentes gráficos, testes de desempenho, acesso a memória flash e outros recursos do dispositivo via IDE, entre outras funcionalidades. O SDK deve ser baixado separado e corretamente configurado se a ferramenta escolhida para desenvolvimento for o Eclipse. Todas essas funcionalidades estão inclusas no Android Studio, que foi feito especificamente para construção de aplicativos Android.

Após fazer o download do Android Studio, basta fazer o download das APIs desejadas durante a própria instalação do mesmo e utilizar do recurso da própria IDE para criar um projeto Android, que já vem com uma estrutura pronta para ser trabalhada, separando e categorizando código fonte e outros recursos utilizados no desenvolvimento. O Eclipse IDE foi utilizado como padrão por um bom tempo antes do lançamento oficial do Android Studio, e também monta uma boa estrutura de projeto, embora diferente da utilizada pelo Android Studio.

É necessário especificar a versão alvo do sistema para o qual se está desenvolvendo. Para manter a compatibilidade, geralmente desenvolvedores utilizam como versão mínima a 2.3 ou anterior, embora para utilizar alguns recursos seja necessário utilizar uma API mínima mais recente. Todas as APIs utilizadas precisam ser baixadas pela própria ferramenta de download do SDK ou automaticamente na instalação da IDE. Para desenvolver para Android kitkat 4.4.2 com compatibilidade com Android 2.3 por exemplo, deve-se obter ambas APIs. Cada vez mais as versões mais antigas estão deixando de ser utilizadas. Desenvolvedores de versões alternativas do Android como o Cyanogemod, vem dando suporte e oportunidade de update da plataforma para dispositivos cujo suporte para atualizações já foi abandonado pelo próprio fabricante, ajudando a fazer com que mesmo usuários mais antigos possam utilizar versões mais recentes do sistema Android. A grande maioria dos dispositivos em 2015 já utiliza API maior que a 15 segundo a própria ferramenta de desenvolvimento.

Juntamente com o SDK, o desenvolvedor tem acesso a uma ferramenta de criação de dispositivos virtuais AVD (Android Virtual Devices) para poder executar as aplicações sendo desenvolvidas sem a necessidade de um dispositivo físico disponível para esse fim. Entretanto vários recursos do sistema não podem ser utilizados por dispositivos virtuais, como por exemplo o GPS e o bluetooth. Nesses casos, é necessário um dispositivo físico para o desenvolvimento de aplicativos. Qualquer dispositivo pode ser utilizado, desde que a versão Android que ele apresente seja compatível com o aplicativo sendo desenvolvido e tenha ativado no sistema as opções de depuração USB.

Para o desenvolvimento para o AOSP, é necessário um dispositivo com bootloader desbloqueável, de forma que seja possível fazer o flash das imagens geradas pela compilação do sistema no dispositivo físico. Os dispositivos Nexus distribuídos pela própria Google são os mais recomendados para desenvolvedores e contribuidores para o código do sistema, uma vez que todos tem seu bootloader desbloqueado e podem ser modificados mais facilmente. Muitos dispositivos, embora não todos, podem ser utilizados para esse fim, desde que tenham bootloader desbloqueado. É importante ressaltar que fazer flash das imagens do sistema para um dispositivo físico requer que o mesmo seja restaurado para configuração de fábrica, removendo todos os dados presentes no mesmo, e resultará na perda de outras versões anteriormente instaladas do sistema. É preciso ter bastante cuidado para não danificar o dispositivo físico tentando fazer instalação de outras versões do sistema sem tomar as precauções necessárias.

Quando se desenvolvendo para o AOSP, é mais difícil ter uma visão total do software sendo modificado, pois o código fonte do sistema é muito extenso. Para carregar todo o código da api Java na memória da IDE Eclipse por exemplo, é necessário fazer uma alteração nas configurações da ferramenta para que ela utilize mais memória (talvez alguns GB de RAM sejam necessários). Muitas vezes a melhor solução é fazer modificações isoladas em arquivos distintos em algum editor de texto qualquer sem ter o recurso de compilação automática das IDEs que ajudam a identificar erros em tempo de codificação. Nesses casos é necessária uma maior experiência do desenvolvedor para uma modificação consciente e cuidadosa nos arquivos de código fonte do sistema operacional.

Testes

editar

Testes de software consistem em verificar se o produto de software se comporta da forma esperada em um determinado conjunto de casos específicos, selecionados com o intuito de representar o maior número de situações diferentes que podem ocorrer durante o uso do sistema, com o software em execução. Os testes têm que ser projetados para checar se o software está de acordo com as necessidades do usuário, procedimento conhecido como validação, e para verificar se as funcionalidades estão de acordo com a especificação, procedimento conhecido como verificação (IEEE, 2014). Testes podem ser realizados em vários níveis, desde o teste de pequenos trechos de código até a interação entre componentes e o teste da interface gráfica do usuário.

Existem vários tipos de testes aplicáveis a determinados tipos de sistema. De acordo com as necessidades e o ambiente onde o sistema irá funcionar, vários testes podem ser ou não necessários para garantir o funcionamento do sistema sob diversas condições. Sistemas web podem exigir testes de carga e stress para avaliar a quantidade de usuários simultâneos suportados, por exemplo. Sistemas críticos já também necessitam de testes de recuperação, para avaliar a capacidade do sistema de manter ou restaurar seu funcionamento após algum tipo de falta.

Ter uma boa suíte de testes é de grande valia para a manutenção de um produto de software, uma vez que sempre que uma modificação precisar ser feita no sistema, é possível verificar de forma automatizada se algum comportamento foi indevidamente alterado pela modificação realizada.

O sistema Android provê um framework para testes, com várias ferramentas que ajudam a testar o aplicativo sendo desenvolvido em vários níveis, desde testes unitários a testes relacionados ao framework de desenvolvimento e a testes de interface de usuário. Todas as ferramentas necessárias para utilizar a API de testes disponível no framework de desenvolvimento Android são disponibilizadas juntamente com o Android SDK.

Podem existir classes em Java puro que não utilizam a API de desenvolvimento do Android. Conseguir fazer essa separação de classes que utilizam o framework e classes em Java puro pode significar uma maior facilidade em testar determinadas partes da aplicação, uma vez que podem ser diretamente utilizados os já bem difundidos JUnit tests para essas classes. Entretanto, muitas classes são construídas através dos componentes, e o funcionamento das mesmas também precisa ser testado.

As suítes de teste no Android são baseadas em JUnit, e então da mesma forma que é possível utilizar JUnit para desenvolver testes para classes que não utilizam a API Android, é possível utilizar as extensões do JUnit criadas especificamente para testar cada componente do aplicativo sendo desenvolvido. Existem extensões JUnit específicas para cada componente Android, e essas classes contém métodos auxiliares para criar Mock Objects. Estes são criados para simular outros objetos do contexto de execução real do aplicativo.

O kit de desenvolvimento para a plataforma Android inclui ferramentas automatizadas de teste de interface gráfica. O robotium, por exemplo, realiza testes de caixa preta em cima da interface gráfica do aplicativo. São criadas rotinas de teste em Java semelhantes ao JUnit, com asserts para validar os resultados. Com ele é possível criar rotinas robustas de testes para validar critérios de aceitação pré-definidos, simulando interações do usuário com uma ou várias activities. Existe a ferramenta Monkeyrunner, onde se cria scripts em Python para instalar e executar algum aplicativo, enviando comandos e cliques para o mesmo, e salvando screenshots do dispositivo no computador com resultados. Há também a ferramenta Monkey, que é utilizada para fazer testes de stress no aplicativo gerando inputs pseudo aleatórios.

Manutenção

editar

A manutenção de software trata dos esforços de desenvolvimento com o software já em produção, isto é, em funcionamento no seu devido ambiente. Problemas que passaram despercebidos durante as fases de construção e testes são encontrados e corrigidos durante a manutenção do sistema. Da mesma forma, o usuário pode requisitar novas funcionalidades que ele não havia pensado antes do uso do sistema, e o desenvolvimento dessas novas funcionalidades é também tratado como manutenção uma vez que o software já se encontra em produção, um processo conhecido como evolução de software. Revisões de código e esforços com manutenibilidade também podem ser consideradas atividades de manutenção, embora possam acontecer antes do sistema entrar em produção.

A manutenção de software geralmente acontece por período mais longo que as demais fases do desenvolvimento do software citadas nos tópicos anteriores, ocupando a maior parte do ciclo de vida do produto.

A separação de componentes independentes apresentados aqui é de grande valia para a manutenibilidade do sistema. Essa separação permite que componentes tenham sua funcionalidade específica melhor compreendida e possam ser substituídos sem grandes impactos nos demais.

Atividades de design de software devem ser reforçadas para garantir uma fase de manutenção com a menor quantidade de problemas possível. Uma arquitetura modularizada é mais fácil de ser entendida e modificada e consequentemente mantida. Também é importante que se utilize de padrões de codificação, identação e documentação para que a manutenção seja facilitada inclusive para desenvolvedores que não tem familiaridade com o código desenvolvido. Empresas tendem a colocar equivocadamente engenheiros junior para dar manutenção a sistemas e engenheiros mais experientes para desenvolver novos projetos, e adotar práticas de desenvolvimento que agem em favor à manutenibilidade ajudam a amenizar os problemas causados por esse tipo de alocação de recursos humanos.

Os resultados de métricas que refletem decisões arquiteturais geralmente tem relação com a manutenibilidade do software. Alto acoplamento entre objetos, por exemplo, indica que uma mudança em um pequeno trecho de código pode trazer resultados catastróficos no restante do software.

Sendo um sistema de código aberto, o Android permite que o desenvolvedor possa o analisar e consequentemente o entender a ponto de corrigir bugs do sistema, criar funcionalidades novas, e também portá-lo para novos hardwares (GANDHEWAR; SHEIKH, 2010). Isso é um ponto importante para atividades de manutenção do sistema Android como um todo, e permitiu que a plataforma crescesse de forma extremamente acelerada em um pequeno espaço de tempo. Um dos motivos para a própria plataforma Linux estar em um estado tão estável nos dias atuais foi os anos que a mesma teve de contribuição da comunidade sendo um software livre e portanto tendo seu código aberto a qualquer desenvolvedor, assim como o sistema Android.

Inserido no contexto de manutenção e evolução do sistema Android, este trabalho avalia resultado de métricas em um sistema operacional consolidado e amplamente utilizado para auxiliar qualquer etapa que envolva manipulação de código fonte no ciclo de desenvolvimento de outros projetos relacionados para esta plataforma. Desenvolvedores poderão utilizar resultados deste estudo para tomar decisões relacionadas a remodelagem e refatoração de seus projetos que já estejam em produção, a fim de melhorar sua qualidade e facilitar sua evolução.

Em linhas gerais, impactos positivos podem ser vistos em todas as etapas do ciclo de vida do software quando se monitora o desenvolvimento do produto desde sua concepção.