Dentro dos pacotes OTA

O sistema cria o binário do atualizador de bootable/recovery/updater e o usa em um pacote OTA.

O pacote em si é um arquivo .zip (ota_update.zip, incremental_ota_update.zip) que contém o binário executável META-INF/com/google/android/update-binary .

O Updater contém várias funções integradas e um intérprete para uma linguagem de script extensível (edify) que oferece suporte a comandos para tarefas típicas relacionadas à atualização. O atualizador procura um script no arquivo .zip do pacote META-INF/com/google/android/updater-script.

Observação:usar o script edify e/ou as funções integradas não é uma atividade comum, mas pode ser útil se você precisar depurar o arquivo de atualização.

Sintaxe do Edify

Um script edify é uma única expressão em que todos os valores são strings. Strings vazias são falsos em um contexto booleano, e todas as outras strings são verdadeiras. O Edify é compatível com os seguintes operadores (com os significados usuais):

(expr )
 expr + expr  # string concatenation, not integer addition
 expr == expr
 expr != expr
 expr && expr
 expr || expr
 ! expr
 if expr then expr endif
 if expr then expr else expr endif
 function_name(expr, expr,...)
 expr; expr

Qualquer string dos caracteres a-z, A-Z, 0-9, _, :, /, . que não é uma palavra reservada é considerado um literal de string. (As palavras reservadas são if else e endif.) Os literais de string também podem aparecer entre aspas duplas. Essa é a forma de criar valores com espaços em branco e outros caracteres que não estão no conjunto acima. \n, \t, \" e \\ servem como caracteres de escape em strings entre aspas, assim como \x##.

Os operadores && e || são de curto-circuito. O lado direito não é avaliado se o resultado lógico é determinado pelo lado esquerdo. Os seguintes são equivalentes:

e1 && e2
if e1 then e2 endif

O operador ; é um ponto de sequência. Isso significa avaliar primeiro o lado esquerdo e depois o lado direito. O valor é o valor da expressão à direita. Um ponto e vírgula também pode aparecer após uma expressão, para que o efeito simule instruções no estilo C:

prepare();
do_other_thing("argument");
finish_up();

Funções integradas

A maioria das funcionalidades de atualização está contida nas funções disponíveis para execução por scripts. Na verdade, elas são macros, e não funções, no sentido do Lisp, já que não precisam avaliar todos os argumentos. A menos que indicado de outra forma, as funções retornam true em caso de sucesso e false em caso de erro. Se você quiser que os erros abortem a execução do script, use as funções abort() e/ou assert(). O conjunto de funções disponíveis no atualizador também pode ser estendido para fornecer funcionalidades específicas do dispositivo.

abort([msg])
Interrompe a execução do script imediatamente, com a msg opcional. Se o usuário tiver ativado a exibição de texto, msg vai aparecer no registro de recuperação e na tela.
assert(expr[, expr, ...])
Avalia cada expr por vez. Se algum for falso, aborta imediatamente a execução com a mensagem "assert failed" e o texto de origem da expressão com falha.
apply_patch(src_file, tgt_file, tgt_sha1, tgt_size, patch1_sha1, patch1_blob, [...])
Aplica um patch binário ao src_file para produzir o tgt_file . Se o destino desejado for o mesmo que a origem, transmita "-" para tgt_file . tgt_sha1 e tgt_size são o hash SHA1 final esperado e o tamanho do arquivo de destino. Os argumentos restantes precisam vir em pares: um hash SHA1 (uma string hexadecimal de 40 caracteres) e um blob. O blob é o patch a ser aplicado quando o conteúdo atual do arquivo de origem tiver o SHA1 fornecido.

O patch é feito de maneira segura, garantindo que o arquivo de destino tenha o hash e o tamanho SHA1 desejados ou que ele não seja alterado, ou seja, que ele não seja deixado em um estado intermediário irrecuperável. Se o processo for interrompido durante o patch, o arquivo de destino poderá estar em um estado intermediário. Uma cópia existe na partição de cache, para que a reinicialização da atualização possa atualizar o arquivo.

A sintaxe especial é compatível para tratar o conteúdo de partições de dispositivo de tecnologia de memória (MTD, na sigla em inglês) como arquivos, permitindo a correção de partições brutas, como a inicialização. Para ler uma partição MTD, você precisa saber quantos dados quer ler, já que a partição não tem uma noção de fim de arquivo. É possível usar a string "MTD:partition:size_1:sha1_1:size_2: sha1_2" como um nome de arquivo para ler a partição especificada. É necessário especificar pelo menos um par (size, sha-1). Você pode especificar mais de um se houver várias possibilidades para o que você espera ler.

apply_patch_check(filename, sha1[, sha1, ...])
Vai retornar verdadeiro se o conteúdo de filename ou a cópia temporária na partição de cache (se presente) tiver uma soma de verificação SHA1 igual a um dos valores de sha1 fornecidos. Os valores sha1 são especificados como 40 dígitos hexadecimais. Essa função é diferente de sha1_check(read_file(filename), sha1 [, ...]) porque sabe verificar a cópia da partição do cache. Portanto, apply_patch_check() terá sucesso mesmo que o arquivo tenha sido corrompido por uma apply_patch() update interrompida.
apply_patch_space(bytes)
Vai retornar verdadeiro se pelo menos bytes de espaço em branco estiverem disponíveis para aplicar patches binários.
concat(expr[, expr, ...])
Avalia cada expressão e as concatena. O operador + é o açúcar sintático para essa função no caso especial de dois argumentos, mas a forma da função pode receber qualquer número de expressões. As expressões precisam ser strings. Não é possível concatenar blobs.
file_getprop(filename, key)
Lê o filename fornecido, o interpreta como um arquivo de propriedades (por exemplo, /system/build.prop) e retorna o valor da chave especificada ou a string vazia se a chave não estiver presente.
format(fs_type, partition_type, location, fs_size, mount_point)
Reformata uma determinada partição. Tipos de partição com suporte:
  • fs_type="yaffs2" e partition_type="MTD". O local precisa ser o nome da partição MTD. Um sistema de arquivos yaffs2 vazio é criado ali. Os argumentos restantes não são usados.
  • fs_type="ext4" e partition_type="EMMC". O local precisa ser o arquivo do dispositivo para a partição. Um sistema de arquivos ext4 vazio é criado. Se fs_size for zero, o sistema de arquivos ocupará a partição inteira. Se fs_size for um número positivo, o sistema de arquivos vai usar os primeiros bytes fs_size da partição. Se fs_size for um número negativo, o sistema de arquivos vai ocupar tudo, exceto os últimos bytes |fs_size| da partição.
  • fs_type="f2fs" e partition_type="EMMC". O local precisa ser o arquivo de dispositivo da partição. fs_size precisa ser um número não negativo. Se fs_size for zero, o sistema de arquivos ocupará a partição inteira. Se fs_size for um número positivo, o sistema de arquivos vai usar os primeiros bytes fs_size da partição.
  • mount_point precisa ser o ponto de montagem futuro do sistema de arquivos.
getprop(key)
Esse método retorna o valor da propriedade do sistema key (ou a string vazia, se ela não estiver definida). Os valores de propriedade do sistema definidos pela partição de recuperação não são necessariamente os mesmos do sistema principal. Essa função retorna o valor em recuperação.
greater_than_int(a, b)
Vai retornar verdadeiro se e somente se a (interpretado como um número inteiro) for maior que b (interpretado como um número inteiro).
ifelse(cond, e1[, e2])
Avalia cond e, se for verdadeiro, avalia e retorna o valor de e1. Caso contrário, avalia e retorna e2 (se presente). A construção "if ... else ... then ... endif" é apenas uma facilidade sintática para essa função.
is_mounted(mount_point)
Retorna verdadeiro se houver um sistema de arquivos montado em mount_point.
is_substring(needle, haystack)
Retorna verdadeiro se needle for uma substring de haystack.
less_than_int(a, b)
Vai retornar verdadeiro se a (interpretado como um número inteiro) for menor que b (interpretado como um número inteiro).
mount(fs_type, partition_type, name, mount_point)
Monta um sistema de arquivos de fs_type em mount_point. partition_type precisa ser uma destas opções:
  • MTD. O nome é o nome de uma partição MTD (por exemplo, system, userdata). Consulte /proc/mtd no dispositivo para uma lista completa.
  • EMMC.

A recuperação não monta nenhum sistema de arquivos por padrão (exceto o cartão SD se o usuário estiver fazendo uma instalação manual de um pacote do cartão SD). O script precisa montar todas as partições que ele precisa modificar.

package_extract_dir(package_dir, dest_dir)
Extrai todos os arquivos do pacote abaixo de package_dir e os grava na árvore correspondente abaixo de dest_dir. Todos os arquivos existentes são substituídos.
package_extract_file(package_file[, dest_file])
Extrai um único package_file do pacote de atualização e o grava em dest_file, substituindo os arquivos atuais, se necessário. Sem o argumento dest_file, retorna o conteúdo do arquivo de pacote como um blob binário.
read_file(filename)
filename e retorna o conteúdo como um blob binário.
run_program(path[, arg, ...])
Executa o binário em path, transmitindo args. Retorna o status de saída do programa.
set_progress(frac)
Define a posição do medidor de progresso no bloco definido pela chamada show_progress() mais recente. frac precisa estar no intervalo [0,0, 1,0]. O medidor de progresso nunca volta para trás. As tentativas de fazer isso são ignoradas.
sha1_check(blob[, sha1])
O argumento blob é um blob do tipo retornado por read_file() ou a forma de um argumento de package_extract_file() . Sem argumentos sha1, essa função retorna o hash SHA1 do blob (como uma string hexadecimal de 40 dígitos). Com um ou mais argumentos sha1, essa função retorna o hash SHA1 se ele for igual a um dos argumentos ou a string vazia se ele não for igual a nenhum deles.
show_progress(frac, secs)
Avança o medidor de progresso para a próxima fração de comprimento nos segundos (precisa ser um número inteiro). O valor de segundos pode ser 0. Nesse caso, o medidor não é avançado automaticamente, mas pelo uso da função set_progress() definida acima.
sleep(secs)
Coloca em suspensão por secs segundos (precisa ser um número inteiro).
stdout(expr[, expr, ...])
Avalia cada expressão e descarta o valor dela no stdout. Útil para depuração.
tune2fs(device[, arg, …])
Ajusta os parâmetros configuráveis args no device.
ui_print([text, ...])
Concatena todos os argumentos de texto e imprime o resultado na interface (onde ele vai ficar visível se o usuário tiver ativado a exibição de texto).
unmount(mount_point)
Desmonta o sistema de arquivos montado em mount_point.
wipe_block_device(block_dev, len)
Exclui permanentemente os bytes len do dispositivo de bloco block_dev.
wipe_cache()
Faz com que a partição de cache seja apagada no final de uma instalação bem-sucedida.
write_raw_image(filename_or_blob, partition)
Grava a imagem em filename_or_blob na partição MTD. filename_or_blob pode ser uma string que nomeia um arquivo local ou um argumento com valor de blob que contém os dados a serem gravados. Para copiar um arquivo do pacote OTA para uma partição, use: write_raw_image(package_extract_file("zip_filename"), "partition_name");

Observação:antes do Android 4.1, apenas os nomes de arquivos eram aceitos. Para fazer isso, os dados precisavam ser descompactados em um arquivo local temporário.