O sistema cria o binário do atualizador de bootable/recovery/updater
e o usa
em um pacote OTA.
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 umaapply_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.
-
MTD. O nome é o nome de uma partição MTD (por exemplo, system, userdata). Consulte
-
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)
- Lê 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 depackage_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.