System odzyskiwania zawiera kilka punktów zaczepienia do wstawiania kodu powiązanego z urządzeniem, dzięki czemu funkcja OTA Aktualizacje mogą również aktualizować elementy urządzenia inne niż system Android (np. pasmo podstawowe lub procesora radiowego).
Poniższe sekcje i przykłady dostosowują urządzenie tardis wyprodukowane przez yoyodyne.
Mapa partycji
Od Androida 2.3 platforma obsługuje urządzenia flash eMMc i system plików ext4 z systemem na tych urządzeniach. Obsługuje także urządzenia flash Memory Technology Device (MTD) oraz procesory Yaffs2 systemu plików ze starszych wersji.
Plik mapy partycji jest określany przez TARGET_RECOVERY_FSTAB; jest używany przez w przypadku plików binarnych systemu odzyskiwania i narzędzi do tworzenia pakietów. Możesz podać nazwę pliku mapy w TARGET_RECOVERY_FSTAB w pliku BoardConfig.mk.
Przykładowy plik mapy partycji może wyglądać tak:
device/yoyodyne/tardis/recovery.fstab
# mount point fstype device [device2] [options (3.0+ only)] /sdcard vfat /dev/block/mmcblk0p1 /dev/block/mmcblk0 /cache yaffs2 cache /misc mtd misc /boot mtd boot /recovery emmc /dev/block/platform/s3c-sdhci.0/by-name/recovery /system ext4 /dev/block/platform/s3c-sdhci.0/by-name/system length=-4096 /data ext4 /dev/block/platform/s3c-sdhci.0/by-name/userdata
Z wyjątkiem punktu /sdcard
, który jest opcjonalny, wszystkie punkty podłączania w tej
przykład musi być zdefiniowany (urządzenia mogą też dodawać dodatkowe partycje). Dostępnych jest 5 obszarów obsługiwanych przez
typy systemów plików:
- yaffy2
-
System plików yaffs2 na urządzeniu flash MTD. „urządzenie” musi być nazwą partycji MTD
i muszą występować w języku:
/proc/mtd
. - mtd
-
Nieprzetworzona partycja MTD używana na potrzeby partycji z możliwością rozruchu, takich jak uruchamianie i przywracanie. MTD nie
podłączone, ale punkt podłączania jest używany jako klucz do zlokalizowania partycji. „urządzenie”
musi być nazwą partycji MTD w
/proc/mtd
. - ext4
- System plików ext4 na urządzeniu flash eMMc. „urządzenie” musi być ścieżką urządzenia blokującego.
- EMC
- Urządzenie z nieprzetworzonym blokiem eMMc używane na partycjach z możliwością rozruchu, np. podczas uruchamiania i przywracania. Podobne do typu mtd, eMMc nigdy nie jest podłączany, ale ciąg punktu podłączania jest używany do urządzenie w tabeli.
- vfat
-
System plików FAT umieszczony na urządzeniu blokowym, zwykle do przechowywania pamięci zewnętrznej, np. karty SD.
urządzenie jest urządzeniem blokującym; device2 to drugie urządzenie blokowe, które system próbuje podłączyć, jeśli
nie można zainstalować głównego urządzenia (w celu zapewnienia zgodności z kartami SD, które mogą
sformatowanego za pomocą tabeli partycji).
Wszystkie partycje muszą być podłączone w katalogu głównym (tzn. wartość punktu podłączania musi być zaczyna się od ukośnika i nie ma innych ukośników). To ograniczenie dotyczy tylko podłączania systemy plików w trakcie przywracania; główny system pozwala zamontować je w dowolnym miejscu. Katalogi
/boot
,/recovery
i/misc
powinny być typami nieprzetworzonych (mtd lub emmc), natomiast katalogi/system
,/data
,/cache
i/sdcard
(jeśli są dostępne) powinny być typami systemu plików (yaffs2, ext4 lub vfat).
Począwszy od Androida 3.0 plikrecovery.fstab otrzymuje dodatkowe pole opcjonalne, opcji. Obecnie jedyną zdefiniowaną opcją jest length , która pozwala określ długość partycji. Ta długość jest używana podczas ponownego formatowania partycji np. w przypadku partycji danych użytkownika podczas operacji czyszczenia danych lub przywracania do ustawień fabrycznych, partycji systemowej podczas instalacji pełnego pakietu OTA). Jeśli długość jest ujemna, rozmiar do sformatowania zostanie dodany przez dodanie wartości długości do rzeczywistego rozmiaru partycji. Dla: instancji z ustawieniem „length=-16384” oznacza, że ostatnie 16 KB tej partycji nie zostanie zastąpione po sformatowaniu partycji. Obsługuje takie funkcje jak szyfrowanie partycji danych użytkownika (gdzie metadane szyfrowania są przechowywane na końcu partycji, która nie powinny być zastępowane).
Uwaga: pola device2 i options są opcjonalne, tworząc niejasności podczas analizowania. Jeśli wpis w czwartym polu wiersza zaczyna się znakiem „/” jest uważany za wpis device2 ; jeśli wpis nie zaczyna się od znaku „/” jest uważany za pole options.
Animacja podczas uruchamiania
Producenci urządzeń mogą dostosowywać animację wyświetlaną na urządzeniu z Androidem. właśnie się uruchamia. W tym celu utwórz plik ZIP uporządkowany i umieszczony zgodnie z specyfikacji w bootanimation format.
Dla: urządzenia Android Things, możesz przesłać skompresowany plik w konsoli Android Things, aby uwzględnić obrazy wybranego produktu.
Uwaga: te obrazy muszą być zgodne ze wskazówkami dotyczącymi marki Android. Wskazówki dotyczące marki: zapoznaj się z sekcją dotyczącą Androida Marketing partnera Centrum.
Interfejs przywracania
Aby zapewnić obsługę urządzeń z różnym dostępnym sprzętem (przyciski fizyczne, diody LED, ekrany itp.), możesz dostosować interfejs odzyskiwania tak, aby wyświetlać stan i mieć dostęp do obsługiwanych ręcznie ukrytych funkcji na każdym urządzeniu.
Twoim celem jest zbudowanie małej biblioteki statycznej z kilkoma obiektami w C++, które zapewniają
funkcji dostępnych na poszczególnych urządzeniach. Plik
Domyślnie używana jest właściwość bootable/recovery/default_device.cpp
, która sprawia, że
który ma być kopiowany podczas zapisywania wersji tego pliku na urządzenie.
Uwaga: może się wyświetlić komunikat Brak polecenia. Aby przełączyć tekstu, naciśnij i przytrzymaj przycisk zasilania. Jeśli Twoje urządzenia nie mają Przytrzymaj dowolny przycisk, aby przełączyć tekst.
device/yoyodyne/tardis/recovery/recovery_ui.cpp
#include <linux/input.h> #include "common.h" #include "device.h" #include "screen_ui.h"
Funkcje nagłówka i elementu
Klasa urządzenia wymaga funkcji zwracania nagłówków i elementów, które są widoczne w ukrytym w menu odzyskiwania. Nagłówki opisują sposób obsługi menu (np. elementy sterujące do zmiany/wybierania pola zaznaczonego elementu).
static const char* HEADERS[] = { "Volume up/down to move highlight;", "power button to select.", "", NULL }; static const char* ITEMS[] = {"reboot system now", "apply update from ADB", "wipe data/factory reset", "wipe cache partition", NULL };
Uwaga: długie linie są obcinane (nie zawijane), więc zachowaj szerokość z myślą o ekranie urządzenia.
Dostosuj klucz kontrolny
Następnie określ implementację RecoveryUI na urządzeniu. W tym przykładzie zakładamy, że
tardis ma ekran, możesz więc dziedziczyć
Implementacja ScreenRecoveryUI (zobacz instrukcje dotyczące
urządzeń bez ekranu). Jedyna funkcja do
„Dostosuj w interfejsie ScreenRecoveryUI” to CheckKey()
, który wykonuje początkowy okres
asynchroniczna obsługa kluczy:
class TardisUI : public ScreenRecoveryUI { public: virtual KeyAction CheckKey(int key) { if (key == KEY_HOME) { return TOGGLE; } return ENQUEUE; } };
Stałe KEY
Stałe KEY_* są zdefiniowane w polu linux/input.h
. CheckKey()
to
niezależnie od tego, co dzieje się w dalszej części przywracania systemu: gdy menu jest wyłączone,
jest włączona, podczas instalacji pakietu, podczas czyszczenia danych użytkownika itd. Może zwrócić jedną z czterech
stałe:
- PRZEŁĄCZ. Włącz lub wyłącz wyświetlanie menu lub logu tekstowego
- URUCHOM PONOWNIE. Natychmiast zrestartuj urządzenie
- IGNORE. Zignoruj to naciśnięcie klawisza
- ENQUEUE (Rozpocznij kolejkę). Umieść ten klawisz w kolejce, aby został użyty synchronicznie (tj. przez system odzyskiwania systemu menu, jeśli wyświetlacz jest włączony)
Funkcja CheckKey()
jest wywoływana za każdym razem, gdy po wystąpieniu zdarzenia klucza następuje zdarzenie kluczowe dla
ten sam klucz. (Sekwencja zdarzeń A, kolejne, A, dalej, Dalej, daje tylko wynik
CheckKey(B)
). CheckKey()
może dzwonić
IsKeyPressed()
, by sprawdzić, czy przytrzymują inne klawisze. (W polu powyżej
sekwencja kluczowych zdarzeń, jeśli funkcja CheckKey(B)
nazwała ją IsKeyPressed(A)
.
zwracałaby wartość „prawda”).
CheckKey()
może zachować stan w swojej klasie; – może to pomóc w wykrywaniu
sekwencji klawiszy. W tym przykładzie przedstawiono nieco bardziej skomplikowaną konfigurację: wyświetlacz przełącza się przez
przytrzymując przycisk zasilania i wciskając przycisk zwiększania głośności, urządzenie można natychmiast zrestartować przez
naciskanie przycisku zasilania 5 razy z rzędu (bez żadnych dodatkowych klawiszy):
class TardisUI : public ScreenRecoveryUI { private: int consecutive_power_keys; public: TardisUI() : consecutive_power_keys(0) {} virtual KeyAction CheckKey(int key) { if (IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) { return TOGGLE; } if (key == KEY_POWER) { ++consecutive_power_keys; if (consecutive_power_keys >= 5) { return REBOOT; } } else { consecutive_power_keys = 0; } return ENQUEUE; } };
ScreenRecoveryUI.
Jeśli używasz własnych obrazów (ikona błędu, animacja instalacji, paski postępu) z
ScreenRecoveryUI, możesz ustawić zmienną animation_fps
, aby kontrolować szybkość
klatek na sekundę w animacjach.
Uwaga: obecny skrypt interlace-frames.py
umożliwia
przechowywania informacji animation_fps
w samym obrazie. We wcześniejszych wersjach
Na Androidzie konieczne było samodzielne skonfigurowanie urządzenia animation_fps
.
Aby ustawić zmienną animation_fps
, zastąp zmienną
ScreenRecoveryUI::Init()
w podklasie. Ustaw wartość, a potem wywołaj funkcję
parent Init()
do zakończenia inicjowania. Wartość domyślna (20 kl./s)
odpowiada domyślnym obrazom przywracania; jeśli używasz tych obrazów, nie musisz przesyłać
funkcję Init()
. Szczegółowe informacje o obrazach:
Obrazy interfejsu odzyskiwania
Klasa urządzenia
Po wdrożeniu RecoveryUI zdefiniuj klasę urządzenia (podklasę od klasy
wbudowanej klasy urządzenia). Powinien utworzyć jedną instancję klasy interfejsu i zwrócić tę
z funkcji GetUI()
:
class TardisDevice : public Device { private: TardisUI* ui; public: TardisDevice() : ui(new TardisUI) { } RecoveryUI* GetUI() { return ui; }
Rozpocznij odzyskiwanie
Metoda StartRecovery()
jest wywoływana na początku przywracania, gdy interfejs użytkownika
zostało zainicjowane i po przeanalizowaniu argumentów, ale przed jakimkolwiek działaniem
podjętych działań. Domyślna implementacja nie robi nic, więc nie trzeba podawać jej w dokumencie.
podklasa, jeśli nie masz nic do zrobienia:
void StartRecovery() { // ... do something tardis-specific here, if needed .... }
Podaj menu odzyskiwania i nimi zarządzaj
System wywołuje 2 metody, aby uzyskać listę wierszy nagłówka i listę elementów. W tym zwraca tablice statyczne zdefiniowane na początku pliku:
const char* const* GetMenuHeaders() { return HEADERS; } const char* const* GetMenuItems() { return ITEMS; }
Klawisz menu uchwytu
Następnie podaj funkcję HandleMenuKey()
, która pobiera naciśnięcie klawisza i bieżącą
widoczność menu i zdecyduje, jakie działanie należy podjąć:
int HandleMenuKey(int key, int visible) { if (visible) { switch (key) { case KEY_VOLUMEDOWN: return kHighlightDown; case KEY_VOLUMEUP: return kHighlightUp; case KEY_POWER: return kInvokeItem; } } return kNoAction; }
Ta metoda pobiera kod klucza (który został wcześniej przetworzony i umieszczony w kolejce przez klucz
CheckKey()
obiektu UI) i bieżący stan menu/dziennika tekstowego.
widoczność. Zwracana wartość jest liczbą całkowitą. Jeśli wartość wynosi 0 lub więcej, jest ona traktowana jako
pozycji menu, która jest wywoływana natychmiast (zobacz
InvokeMenuItem()
poniżej). W przeciwnym razie może to być jedna z tych wartości:
wstępnie zdefiniowane stałe:
- kWyróżnijUp, Przenieś wyróżnienie menu na poprzedni element
- kWyróżnijDown. Przenieś wyróżnienie menu na następny element
- kInvokeItem. Wywołaj aktualnie podświetlony element
- kNoAction. Nie rób nic po naciśnięciu tego klawisza
Jak wskazuje widoczny argument, funkcja HandleMenuKey()
jest wywoływana nawet wtedy, gdy menu to
niewidoczny. W przeciwieństwie do funkcji CheckKey()
nie jest wywoływane podczas przywracania
na przykład w celu wyczyszczenia danych lub zainstalowania pakietu – funkcja jest wywoływana tylko wtedy, gdy przywracanie jest bezczynne.
i czekam na dane wejściowe.
Mechanizmy kulki
Jeśli urządzenie jest wyposażone w mechanizm przypominający kulkę (generuje zdarzenia wejściowe typu EV_REL).
i kod REL_Y), przywracanie powoduje naciśnięcie klawiszy KEY_UP i KEY_DOWN przy każdym naciśnięciu
urządzenie wejściowe przypominające kulkę zgłasza ruch na osi Y. Wystarczy, że zmapujesz KEY_UP i
KEY_DOWN zdarzenia na działania w menu. To mapowanie nie występuje w przypadku:
CheckKey()
, więc nie można używać kulki jako wyzwalacza restartu ani
przełączyć wyświetlacz.
Klawisze modyfikujące
Aby sprawdzić, czy klawisze są przytrzymane jako modyfikatory, wywołaj metodę IsKeyPressed()
własnego obiektu UI. Na przykład na niektórych urządzeniach naciśnięcie Alt-W podczas przywracania uruchamiało
czyszczenia danych niezależnie od tego, czy menu było widoczne. Możesz zastosować taki:
int HandleMenuKey(int key, int visible) { if (ui->IsKeyPressed(KEY_LEFTALT) && key == KEY_W) { return 2; // position of the "wipe data" item in the menu } ... }
Uwaga: jeśli atrybut visible ma wartość false (fałsz), nie ma sensu zwracania znaku specjalnego które modyfikują menu (przesuń wyróżnienie, wywołaj podświetlony element), ponieważ aby zobaczyć najciekawszy moment. W razie potrzeby możesz jednak zwrócić te wartości.
Wywołaj element menu
Następnie udostępnij metodę InvokeMenuItem()
, która mapuje pozycje całkowite w tablicy
elementów zwróconych przez GetMenuItems()
zadaniom. W przypadku tablicy elementów w argumencie
przykładu tardis, użyj:
BuiltinAction InvokeMenuItem(int menu_position) { switch (menu_position) { case 0: return REBOOT; case 1: return APPLY_ADB_SIDELOAD; case 2: return WIPE_DATA; case 3: return WIPE_CACHE; default: return NO_ACTION; } }
Ta metoda może zwrócić dowolnego elementu wyliczeniowego BuiltinAction, aby nakazać systemowi wykonanie tej działania (lub elementu NO_ACTION, jeśli system nie ma nic robić). W tym miejscu możesz udostępnić dodatkową funkcję odzyskiwania wykraczającą poza zawartość systemu: dodaj do niej element w w menu, wykonaj je tutaj po wywołaniu tej pozycji menu i zwróć NO_ACTION, aby system nic więcej nie robi.
BuiltinAction zawiera te wartości:
- NO_ACTION. Nic nie rób.
- URUCHOM PONOWNIE. Wyjdź z trybu odzyskiwania i uruchom ponownie urządzenie w normalny sposób.
- APPLY_EXT, APPLY_CACHE, APPLY_ADB_SIDELOAD. Zainstaluj pakiet aktualizacji z różnych miejsc. Więcej informacji znajdziesz w sekcji Wczytywanie z innego urządzenia.
- STORAGE_CACHE. Sformatuj tylko partycję pamięci podręcznej. Potwierdzenie nie jest wymagane, ponieważ to jest stosunkowo nieszkodliwe.
- Wyczyść dane. Ponowne formatowanie partycji danych użytkownika i pamięci podręcznej (nazywanych też danymi fabrycznymi) . Przed kontynuowaniem użytkownik jest proszony o potwierdzenie tego działania.
Ostatnia metoda, WipeData()
, jest opcjonalna i wywoływana przy każdym wyczyszczeniu danych
operacji (za pomocą opcji odzyskiwania za pomocą menu lub po wykonaniu przez użytkownika polecenia
lub przywracania danych fabrycznych z systemu głównego). Ta metoda jest wywoływana przed danymi użytkownika i pamięci podręcznej
zostały wyczyszczone. Jeśli urządzenie przechowuje dane użytkownika w innych miejscach
partycji, usuń je tutaj. Musisz zwrócić 0, aby wskazać powodzenie, oraz drugą wartość
, ale obecnie zwracana wartość jest ignorowana. dane użytkownika i pamięć podręczną.
partycje zostaną wyczyszczone niezależnie od tego, czy zostanie wyświetlony powodzenie, czy niepowodzenie.
int WipeData() { // ... do something tardis-specific here, if needed .... return 0; }
Utwórz urządzenie
Wstaw też stały fragment kodu na końcu plikurecovery_ui.cpp dla polecenia
Funkcja make_device()
, która tworzy i zwraca instancję klasy urządzenia:
class TardisDevice : public Device { // ... all the above methods ... }; Device* make_device() { return new TardisDevice(); }
Utwórz link do odzyskiwania urządzenia i połącz go z nim
Po zakończeniu tworzenia plikurecovery_ui.cpp utwórz go i połącz z przywracaniem na urządzeniu. W Android.mk, utwórz bibliotekę statyczną, która zawiera tylko ten plik w C++:
device/yoyodyne/tardis/recovery/Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := eng LOCAL_C_INCLUDES += bootable/recovery LOCAL_SRC_FILES := recovery_ui.cpp # should match TARGET_RECOVERY_UI_LIB set in BoardConfig.mk LOCAL_MODULE := librecovery_ui_tardis include $(BUILD_STATIC_LIBRARY)
Następnie w konfiguracji tablicy dla tego urządzenia określ bibliotekę statyczną jako wartość TARGET_RECOVERY_UI_LIB.
device/yoyodyne/tardis/BoardConfig.mk [...] # device-specific extensions to the recovery UI TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis
Obrazy interfejsu przywracania
Interfejs przywracania systemu składa się z obrazów. Najlepiej, gdy użytkownicy nigdy nie korzystają z interfejsu: Podczas normalnej aktualizacji telefon uruchamia się ponownie, wypełnia pasek postępu instalacji, i uruchamia się z powrotem do nowego systemu bez udziału użytkownika. W przypadku działania systemu jest problem z aktualizacją, jedyne działanie, jakie może wykonać użytkownik, to zadzwonienie do działu obsługi klienta.
Interfejs w postaci obrazu eliminuje potrzebę lokalizacji. Jednak w Androidzie 5.0 Aktualizacja może wyświetlić wraz z obrazem ciąg tekstowy (np. „Instaluję aktualizację systemu...”). Więcej informacji znajdziesz w artykule Zlokalizowany tekst odzyskiwania.
Android 5.0 i nowsze
Interfejs przywracania Androida 5.0 i nowszych używa 2 głównych obrazów: obrazu błędu i animację instalowania.
Instalująca animację jest reprezentowana jako pojedynczy obraz PNG z różnymi klatkami
animacja z przeplotem w wierszu (dlatego Ilustracja 2 jest zniekształcona). Na przykład w przypadku adresu
Animacja o wymiarach 200 x 200 z 7 klatkami, utwórz pojedynczy obraz o wymiarach 200 x 1400, w którym pierwsza klatka to wiersze 0, 7,
14, 21, ...; druga klatka to wiersze 1, 8, 15, 22, ...; itp. Połączony obraz zawiera
fragment tekstu wskazujący liczbę klatek animacji i liczbę klatek na sekundę
(FPS). Narzędzie bootable/recovery/interlace-frames.py
pobiera zestaw ramek wejściowych
i łączy je w niezbędny obraz złożony używany przez odzyskiwanie.
Obrazy domyślne są dostępne w różnych gęstościach i znajdują się
bootable/recovery/res-$DENSITY/images
(np.
bootable/recovery/res-hdpi/images
). Aby podczas instalacji użyć obrazu statycznego,
wystarczy przesłać obraz ikona_installing.png i ustawić liczbę klatek w
animacja na 0 (ikona błędu nie jest animowana; zawsze jest to obraz statyczny).
Android 4.x i starsze
Interfejs przywracania Androida 4.x i starszych wersji używa obrazu błędu (pokazanego powyżej) oraz obrazu instalację animacji i kilka nakładek obrazów:
Podczas instalacji ekran jest tworzony przez rysunek ikona_installing.png a następnie rysując jedną z ramek nakładanych z odpowiednim odsunięciem. Tutaj jest nakładana, aby zaznaczyć, w którym miejscu na obrazie podstawowym umieszczana jest nakładka:
Kolejne klatki wyświetlają się, rysując tylko następny obraz nad powierzchnią który już istnieje; a obraz podstawowy nie jest ponownie rysowany.
Liczba klatek animacji, żądana szybkość oraz przesunięcia x i y nakładki.
są ustawiane przez zmienne użytkownika klasy ScreenRecoveryUI. W przypadku użycia funkcji
własnych obrazów zamiast domyślnych, zastąp metodę Init()
w
podklasy, aby zmienić te wartości w przypadku obrazów niestandardowych (szczegóły znajdziesz w artykule
ScreenRecoveryUI). Skrypt
Aplikacja bootable/recovery/make-overlay.py
może pomóc w konwersji zestawu ramek obrazu
„obraz podstawowy + nakładki obrazów” potrzebne do regeneracji, w tym obliczenia
wymaganych kompensacji.
Obrazy domyślne znajdują się w: bootable/recovery/res/images
. Aby użyć obrazu statycznego
podczas instalacji, wystarczy przesłać obraz ikona_installing.png i ustawić liczbę
klatki w animacji do 0 (ikona błędu nie jest animowana; zawsze jest to obraz statyczny).
Zlokalizowany tekst odzyskiwania
Android 5.x wyświetla ciąg tekstowy (np. „Instalowanie aktualizacji systemu...”) oraz . Po uruchomieniu głównego systemu główny system przekazuje aktualne ustawienia regionalne użytkownika jako plik wiersza poleceń do przywracania. Każda wiadomość do wyświetlenia w ramach odzyskiwania obejmuje drugą z wyrenderowanymi wstępnie ciągami tekstowymi dla tego komunikatu w każdym języku.
Przykładowy obraz przedstawiający ciągi tekstowe do odzyskiwania konta:
Tekst odzyskiwania może zawierać te komunikaty:
- Instaluję aktualizację systemu...
- Błąd!
- Usuwam... (podczas czyszczenia/przywrócenia danych do ustawień fabrycznych)
- Brak polecenia (gdy użytkownik ręcznie uruchamia przywracanie)
Aplikacja na Androida w: bootable/recovery/tools/recovery_l10n/
renderuje tłumaczenia
wiadomości i tworzy obraz złożony. Informacje o korzystaniu z tej aplikacji znajdziesz w
komentarze w
bootable/recovery/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java
Gdy użytkownik ręcznie uruchomi system przywracania, język może być niedostępny, a tekst wyświetlenie. Nie używaj wiadomości tekstowych o znaczeniu krytycznym w procesie odzyskiwania konta.
Uwaga: ukryty interfejs, który wyświetla komunikaty dziennika i pozwala użytkownikowi na opcja wyboru czynności z menu jest dostępna tylko w języku angielskim.
Paski postępu
Pod głównym obrazem (lub animacją) mogą pojawić się paski postępu. Pasek postępu jest tworzony przez Łącząc dwa obrazy wejściowe o tym samym rozmiarze:
Lewy koniec obrazu fill jest wyświetlany obok prawego końca pola pusty obraz, by utworzyć pasek postępu. Położenie granicy między nimi Obrazy są zmieniane, by odzwierciedlić postęp. Na przykład w przypadku powyższych par obrazów wejściowych wyświetl:
Możesz udostępnić wersje tych zdjęć dostosowane do urządzenia, umieszczając je w (w tym
przykład) device/yoyodyne/tardis/recovery/res/images
, Nazwy plików muszą być zgodne z tymi wymienionymi powyżej. w przypadku znalezienia pliku w tym katalogu
system kompilacji używa go zamiast odpowiedniego obrazu domyślnego. Tylko PNG w RGB lub
Obsługiwany jest format RGBA z 8-bitową głębią kolorów.
Uwaga: w Androidzie 5.x, jeśli język jest znany do odzyskiwania i jest używany w języku pisanym od prawej do lewej (RTL) (arabski, hebrajski itp.), pasek postępu wypełnia się od prawej do lewej Użytkownik rozłączył się.
Urządzenia bez ekranów
Nie wszystkie urządzenia z Androidem mają ekrany. Jeśli Twoje urządzenie jest urządzeniem bez interfejsu graficznego lub ma interfejsu audio, może być konieczne bardziej zaawansowane dostosowanie interfejsu odzyskiwania. Zamiast tego utworzenia podklasy ScreenRecoveryUI bezpośrednio podklasy swojej klasy nadrzędnej RecoveryUI.
RecoveryUI udostępnia metody obsługi interfejsu niższego poziomu, np. „przełączanie wyświetlacza”,
„zaktualizuj pasek postępu”, „pokaż menu”, „zmień wybór w menu”, itp. Możesz zmienić
aby odpowiednio dostosować interfejs do urządzenia. Może Twoje urządzenie ma diody LED
możesz używać różnych kolorów lub wzorów migających, aby wskazać stan, albo zagrać
audio. (Być może w ogóle nie chcesz obsługiwać menu ani trybu wyświetlania tekstu,
zablokuj dostęp do nich za pomocą funkcji CheckKey()
i
Implementacje HandleMenuKey()
, które nigdy nie włączają wyświetlania ani nie wybierają menu
elementu. W takiej sytuacji wiele metod RecoveryUI, które musisz podać, może być pustych.
wycinki).
Deklarację interfejsu RecoveryUI znajdziesz na bootable/recovery/ui.h
.
które należy wspierać. Interfejs RecoveryUI jest abstrakcyjny – niektóre metody są całkowicie wirtualne i muszą być dostarczane przez
podklas, ale zawiera kod do przetwarzania kluczowych danych wejściowych. Możesz to zmienić
także w sytuacjach, gdy Twoje urządzenie nie ma kluczy lub chcesz przetwarzać je w inny sposób.
Aktualizator
Podczas instalacji pakietu aktualizacji możesz użyć kodu powiązanego z urządzeniem, podając swój dla własnych funkcji rozszerzeń, które można wywoływać ze skryptu aktualizatora. Oto przykład dla urządzenia tardis:
device/yoyodyne/tardis/recovery/recovery_updater.c
#include <stdlib.h> #include <string.h> #include "edify/expr.h"
Każda funkcja rozszerzenia ma ten sam podpis. Argumenty to nazwa, według której
została wywołana funkcja, plik cookie State*
, liczba przychodzących argumentów oraz
tablica wskaźników Expr*
reprezentujących argumenty. Zwracana wartość to
nowo przydzielony element: Value*
.
Value* ReprogramTardisFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); }
Argumenty nie zostały ocenione w momencie wywołania funkcji –
określa, które z nich zostaną ocenione i ile razy. Dzięki temu możesz używać rozszerzeń
w celu wdrożenia własnych struktur sterujących. Call Evaluate()
do oceny
argument Expr*
, który zwraca Value*
. Jeśli Evaluate()
zwraca wartość NULL, należy zwolnić wszystkie przechowywane zasoby i natychmiast zwrócić wartość NULL (to
propagacja przerywa stos edycji). W przeciwnym razie przejmiesz własność zwróconej Wartości i
są odpowiedzialne za wywołanie
FreeValue()
.
Załóżmy, że funkcja wymaga 2 argumentów: klucza z wartością ciągu znaków i obiektu blob image. Możesz odczytać takie argumenty:
Value* key = EvaluateValue(state, argv[0]); if (key == NULL) { return NULL; } if (key->type != VAL_STRING) { ErrorAbort(state, "first arg to %s() must be string", name); FreeValue(key); return NULL; } Value* image = EvaluateValue(state, argv[1]); if (image == NULL) { FreeValue(key); // must always free Value objects return NULL; } if (image->type != VAL_BLOB) { ErrorAbort(state, "second arg to %s() must be blob", name); FreeValue(key); FreeValue(image) return NULL; }
Sprawdzanie wartości NULL i zwalnianie ocenionych wcześniej argumentów może być uciążliwe w przypadku wielu
. Funkcja ReadValueArgs()
może to ułatwić. Zamiast kodu
powyżej można było wpisać:
Value* key; Value* image; if (ReadValueArgs(state, argv, 2, &key, &image) != 0) { return NULL; // ReadValueArgs() will have set the error message } if (key->type != VAL_STRING || image->type != VAL_BLOB) { ErrorAbort(state, "arguments to %s() have wrong type", name); FreeValue(key); FreeValue(image) return NULL; }
ReadValueArgs()
nie obsługuje sprawdzania typu, więc musisz to zrobić tutaj. to więcej
jest to wygodniejsze rozwiązanie z jednym wyrażeniem if kosztem uzyskania nieco mniejszego
określony komunikat o błędzie. Jednak ReadValueArgs()
zajmuje się ocenianiem
każdego argumentu i uwolnienie wszystkich ocenianych wcześniej argumentów (oraz ustawienie przydatnego
), jeśli któraś z ocen zakończy się niepowodzeniem. Za pomocą
ReadValueVarArgs()
funkcjonalności do obliczania liczby zmiennej
argumentów (zwraca tablicę o Value*
).
Po ocenie argumentów wykonaj działanie funkcji:
// key->data is a NUL-terminated string // image->data and image->size define a block of binary data // // ... some device-specific magic here to // reprogram the tardis using those two values ...
Zwracana wartość musi być obiektem Value*
. własność tego obiektu zostanie przekazana do
dzwoniącego. Osoba wywołująca przejmuje własność wszelkich danych wskazywanych przez ten element
Value*
– a konkretnie element danych.
Aby pokazać skuteczność, w tym przypadku należy zwrócić wartość prawda lub fałsz. Pamiętaj:
konwencji, w której pusty ciąg znaków ma wartość false, a pozostałe ciągi mają wartość true. Ty
musi zastosować do zwrócenia obiekt Value z kopią stałego ciągu znaków, ponieważ
rozmówca free()
zrobi i free()
. Nie zapomnij zadzwonić do: FreeValue()
na
i obiektów otrzymanych dzięki ocenie argumentów.
FreeValue(key); FreeValue(image); Value* result = malloc(sizeof(Value)); result->type = VAL_STRING; result->data = strdup(successful ? "t" : ""); result->size = strlen(result->data); return result; }
Funkcja o dowolnej wartości StringValue()
zawija ciąg znaków do nowego obiektu Value.
Użyj go, aby napisać powyższy kod bardziej zwięźle:
FreeValue(key); FreeValue(image); return StringValue(strdup(successful ? "t" : "")); }
Aby podłączyć funkcje do interpretera edify, podaj funkcję
Register_foo
, gdzie foo to nazwa biblioteki statycznej zawierającej
ten kod. Wywołaj RegisterFunction()
, aby zarejestrować funkcje rozszerzenia. Według
konwencja, nazwij funkcje właściwe dla danego urządzenia device.whatever
, których chcesz unikać
koliduje z dodanymi w przyszłości funkcjami wbudowanymi.
void Register_librecovery_updater_tardis() { RegisterFunction("tardis.reprogram", ReprogramTardisFn); }
Teraz możesz skonfigurować plik Makefile, aby utworzyć z kodem bibliotekę statyczną. (Jest to ta sama wartość) użyj pliku cookie do dostosowania interfejsu odzyskiwania opisanego w poprzedniej sekcji; Twoje urządzenie może mieć obie funkcje bibliotek statycznych zdefiniowanych tutaj).
device/yoyodyne/tardis/recovery/Android.mk
include $(CLEAR_VARS) LOCAL_SRC_FILES := recovery_updater.c LOCAL_C_INCLUDES += bootable/recovery
Nazwa biblioteki statycznej musi być taka sama jak nazwa
zawarte w niej funkcje Register_libname
.
LOCAL_MODULE := librecovery_updater_tardis include $(BUILD_STATIC_LIBRARY)
Na koniec skonfiguruj kompilację przywracania do pobrania biblioteki. Dodaj swoją bibliotekę do
TARGET_RECOVERY_UPDATER_LIBS (która może zawierać wiele bibliotek; wszystkie są rejestrowane).
Jeśli Twój kod zależy od innych bibliotek statycznych, które same w sobie nie są komponentami (np.
nie mają funkcji Register_libname
), możesz je wymienić w
TARGET_RECOVERY_UPDATER_EXTRA_LIBS, aby połączyć je z aktualizatorem bez wywoływania jego
(nieistniejącej) funkcji rejestracji. Jeśli na przykład kod urządzenia chciał użyć
zlib, aby zdekompresować dane, umieść tu bibliotekę libz.
device/yoyodyne/tardis/BoardConfig.mk
[...] # add device-specific extensions to the updater binary TARGET_RECOVERY_UPDATER_LIBS += librecovery_updater_tardis TARGET_RECOVERY_UPDATER_EXTRA_LIBS +=
Skrypty aktualizatora w pakiecie OTA mogą teraz wywoływać Twoją funkcję jak każda inna. Aby przeprogramować
Twojego urządzenia tardis, skrypt aktualizacji może zawierać:
tardis.reprogram("the-key", package_extract_file("tardis-image.dat"))
Zastosowanie
wersja z jednym argumentem wbudowanej funkcji package_extract_file()
,
zwraca zawartość pliku wyodrębnionego z pakietu aktualizacji jako obiekt blob do utworzenia
drugi argument nowej funkcji rozszerzenia.
Generowanie pakietów OTA
Ostatnim komponentem jest pokazanie w narzędziach do generowania pakietów OTA informacji o Twoim dane dotyczące konkretnego urządzenia i skrypty aktualizatora, które zawierają wywołania funkcji rozszerzeń.
Najpierw poproś system kompilacji o blob danych dla konkretnego urządzenia. Zakładając, że Twoje dane
jest w lokalizacji device/yoyodyne/tardis/tardis.dat
, zadeklaruj w
do pliku AndroidBoard.mk na urządzeniu:
device/yoyodyne/tardis/AndroidBoard.mk
[...] $(call add-radio-file,tardis.dat)
Możesz też umieścić go w pliku Android.mk, ale musisz go chronić bo wszystkie pliki Android.mk w drzewie są wczytywane niezależnie od używanego urządzenia stworzona przez nas. (Jeśli drzewo obejmuje wiele urządzeń, plik tardis.dat powinien być dodawany tylko podczas podczas tworzenia urządzenia tardis).
device/yoyodyne/tardis/Android.mk
[...] # an alternative to specifying it in AndroidBoard.mk ifeq (($TARGET_DEVICE),tardis) $(call add-radio-file,tardis.dat) endif
Ze względów historycznych są to tzw. pliki radiowe. mogą nie mieć nic wspólnego z
radia urządzenia (jeśli jest dostępne). Są to po prostu nieprzejrzyste bloby danych, do których system kompilacji
pliki ZIP używane przez narzędzia do generowania OTA. Kiedy tworzysz kompilację, plik tardis.dat jest
zapisany w pliku target-files.zip jako RADIO/tardis.dat
. Możesz zadzwonić do nas,
add-radio-file
kilka razy, aby dodać dowolną liczbę plików.
Moduł Pythona
Aby rozszerzyć narzędzia do wersji, utwórz moduł Pythona (o nazwie Releasetools.py). Narzędzia może wywołać połączenie, jeśli jest używany. Przykład:
device/yoyodyne/tardis/releasetools.py
import common def FullOTA_InstallEnd(info): # copy the data into the package. tardis_dat = info.input_zip.read("RADIO/tardis.dat") common.ZipWriteStr(info.output_zip, "tardis.dat", tardis_dat) # emit the script code to install this data on the device info.script.AppendExtra( """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
W przypadku generowania przyrostowego pakietu OTA obsługuje się oddzielna funkcja. Do tego celu Załóżmy na przykład, że musisz przeprogramować pliki tardis tylko wtedy, gdy plik tardis.dat uległ zmianie między 2 kompilacjami.
def IncrementalOTA_InstallEnd(info): # copy the data into the package. source_tardis_dat = info.source_zip.read("RADIO/tardis.dat") target_tardis_dat = info.target_zip.read("RADIO/tardis.dat") if source_tardis_dat == target_tardis_dat: # tardis.dat is unchanged from previous build; no # need to reprogram it return # include the new tardis.dat in the OTA package common.ZipWriteStr(info.output_zip, "tardis.dat", target_tardis_dat) # emit the script code to install this data on the device info.script.AppendExtra( """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
Funkcje modułu
W module dostępne są następujące funkcje (zaimplementuj tylko te, które są Ci potrzebne).
FullOTA_Assertions()
- Wywołane tuż przed rozpoczęciem generowania pełnej aktualizacji OTA. To dobre miejsce na sugerowanie asercji o bieżącym stanie urządzenia. Nie uruchamiaj poleceń skryptu, które wprowadzają zmiany w urządzenia.
FullOTA_InstallBegin()
- Wywoływana po upływie wszystkich asercji dotyczących stanu urządzenia, ale przed wszelkimi zmianami podjętej decyzji. Możesz wydać polecenia dotyczące aktualizacji dla danego urządzenia, które muszą zostać uruchomione przed wszystkie inne elementy na urządzeniu uległy zmianie.
FullOTA_InstallEnd()
- Wywoływana pod koniec generowania skryptu, po poleceniach skryptu w celu zaktualizowania procesu rozruchowego i partycje systemu zostały wyemitowane. Można również emitować dodatkowe polecenia dla aktualizacje na konkretne urządzenia.
IncrementalOTA_Assertions()
-
Podobne do
FullOTA_Assertions()
, ale wywoływane podczas generowania przyrostowego pakietu aktualizacji. IncrementalOTA_VerifyBegin()
- Wywoływana po upłynięciu wszystkich asercji dotyczących stanu urządzenia, ale przed wprowadzeniem zmian podjętej decyzji. Możesz wydać polecenia dotyczące aktualizacji dla danego urządzenia, które muszą zostać uruchomione przed inne funkcje na urządzeniu uległy zmianie.
IncrementalOTA_VerifyEnd()
- Wywoływana na końcu fazy weryfikacji, gdy skrypt zakończy potwierdzanie pliki, które ma dotknąć, mają oczekiwaną treść początkową. Na razie w ramach programu Urządzenie zostało zmienione. Można także wysyłać kod dla dodatkowych, specyficznych dla danego urządzenia weryfikacji danych.
IncrementalOTA_InstallBegin()
- Wywoływana po zweryfikowaniu plików do zastosowania poprawek jako oczekiwane przed, ale przed wprowadzeniem jakichkolwiek zmian. Możesz wydawać polecenia na aktualizacje przeznaczone dla konkretnego urządzenia, które muszą zostać uruchomione, zanim zostaną zmienione jakiekolwiek inne elementy urządzenia.
IncrementalOTA_InstallEnd()
- Podobnie jak w przypadku pełnego pakietu OTA, ta funkcja jest wywoływana na końcu skryptu. gdy polecenia skryptu aktualizują się partycję rozruchową i partycję systemową, emitowanych danych. Możesz też emitować dodatkowe polecenia związane z aktualizacjami dla poszczególnych urządzeń.
Uwaga: jeśli urządzenie utraci zasilanie, instalacja OTA może zostać uruchomiona ponownie od początku. Przygotuj się na obsługę urządzeń, na których te polecenia zostały już uruchomione. w całości lub częściowo.
Przekazywanie funkcji do obiektów informacyjnych
Przekazuj funkcje do jednego obiektu informacyjnego zawierającego różne przydatne elementy:
-
info.input_zip. (Tylko pełne OTA) Obiekt
zipfile.ZipFile
dla pliki wejściowe w formacie .zip. -
info.source_zip. (Tylko przyrostowe OTA) Obiekt
zipfile.ZipFile
dla źródłowe pliki docelowe .zip (kompilacja znajdująca się już na urządzeniu, gdy pakiet przyrostowy jest instalowana). -
info.target_zip, (Tylko przyrostowe OTA) Obiekt
zipfile.ZipFile
dla pliki docelowe .zip (kompilacja pakietów przyrostowych umieszczanych na urządzeniu); -
info.output_zip. Tworzę pakiet; otwarty obiekt
zipfile.ZipFile
za pisanie. Użyj polecenia common.ZipWriteStr(info.output_zip, nazwa pliku, dane), aby dodać do pakietu. -
info.script. Obiekt skryptu, do którego można dołączać polecenia. Zadzwoń do nas
info.script.AppendExtra(script_text)
, aby wstawić tekst do skryptu. Upewnij się, że tekst wyjściowy kończy się średnikiem, aby nie stykał się z wydanymi poleceniami później.
Więcej informacji o obiekcie informacji znajdziesz w dokumentacji, Dokumentacja Python Software Foundation dotycząca archiwów ZIP.
Określ lokalizację modułu
Określ lokalizację skryptu Releasetools.py urządzenia w pliku BoardConfig.mk:
device/yoyodyne/tardis/BoardConfig.mk
[...] TARGET_RELEASETOOLS_EXTENSIONS := device/yoyodyne/tardis
Jeśli zasada TARGET_ReleaseTOOLS_EXTENSIONS nie jest ustawiona, domyślnie przyjmuje się wartość
Katalog domeny $(TARGET_DEVICE_DIR)/../common
(device/yoyodyne/common
w tym przykładzie). Najlepiej jest bezpośrednio zdefiniować lokalizację skryptu Releasetools.py.
Podczas tworzenia urządzenia tardis skrypt Releasetools.py jest dołączany do plików docelowych.
Plik ZIP (META/releasetools.py
).
Po uruchomieniu narzędzi do tworzenia wersji (img_from_target_files
lub
ota_from_target_files
), skrypt Releasetools.py w pliku ZIP z plikami docelowymi, jeśli
obecny, jest preferowany niż ten z drzewa źródłowego Androida. Możesz też wprost
określ ścieżkę do rozszerzeń przeznaczonych na konkretne urządzenia za pomocą parametru -s
(lub
--device_specific
), która ma najwyższy priorytet. Dzięki temu możesz:
poprawić błędy i wprowadzić zmiany w rozszerzeniach narzędzi do wersji i zastosować je do starych
target-files.
Teraz, gdy uruchomisz aplikację ota_from_target_files
, automatycznie pobierze ona
modułu określonego dla urządzenia z pliku ZIP o nazwie target_files i używa go podczas generowania OTA.
pakiety:
./build/make/tools/releasetools/ota_from_target_files \
-i PREVIOUS-tardis-target_files.zip \
dist_output/tardis-target_files.zip \
incremental_ota_update.zip
Możesz też określić rozszerzenia przeznaczone na konkretne urządzenia,
ota_from_target_files
./build/make/tools/releasetools/ota_from_target_files \
-s device/yoyodyne/tardis \
-i PREVIOUS-tardis-target_files.zip \
dist_output/tardis-target_files.zip \
incremental_ota_update.zip
Uwaga: pełną listę opcji znajdziesz w
Komentarze w: ota_from_target_files
build/make/tools/releasetools/ota_from_target_files
Mechanizm wczytywania z innych stron
Przywracanie korzysta z mechanizmu ładowania z nieoficjalnych źródeł, który umożliwia ręczne instalowanie pakietu aktualizacji bez i pobierając go bezprzewodowo przez główny system. Ładowanie z innych aplikacji przydaje się do debugowania lub tworzenia zmian na urządzeniach, na których nie można uruchomić głównego systemu.
Wcześniej aplikacje były ładowane z nieoficjalnych źródeł przez kartę SD urządzenia. cale W przypadku innego urządzenia pakiet można umieścić na karcie SD przy użyciu innego z komputera, a potem włóż do niego kartę SD. Aby dostosować ją do urządzeń z Androidem bez wymiennej pamięci zewnętrznej, Przywracanie obsługuje 2 dodatkowe mechanizmy instalowania z innego urządzenia: ładowanie pakietów z partycji pamięci podręcznej i ładowanie ich przez USB za pomocą narzędzia adb.
Do wywoływania każdego mechanizmu wczytywania z innego urządzenia używana jest metoda Device::InvokeMenuItem()
na urządzeniu
może zwrócić następujące wartości BuiltinAction:
-
APPLY_EXT. Zainstaluj pakiet aktualizacji z pamięci zewnętrznej (
/sdcard
) ). Plikrecovery.fstab musi definiować punkt podłączania/sdcard
. To jest nie można używać na urządzeniach emulujących kartę SD z linkiem symbolicznym do/data
(lub innych) podobnym mechanizmem). Plik/data
zwykle nie jest dostępny do odzyskiwania, ponieważ mogą być zaszyfrowane. W interfejsie odzyskiwania wyświetla się menu plików ZIP w narzędziach/sdcard
i użytkownik może wybrać jeden z nich. -
APPLY_CACHE. Podobnie jak w przypadku wczytywania pakietu ze strony
/sdcard
, różnią się one tym, że Używany jest katalog/cache
(który jest zawsze dostępny do odzyskiwania) . W zwykłym systemie plik/cache
może zapisywać tylko użytkownicy z podwyższonymi uprawnieniami, a jeśli urządzenia nie można uruchomić, to w katalogu/cache
nie będzie można zapisać w ogóle (co czyni ten mechanizm o ograniczonej użyteczności). -
APPLY_ADB_SIDELOAD. Umożliwia użytkownikowi wysłanie pakietu na urządzenie za pomocą kabla USB oraz
oraz narzędzia do tworzenia pakietu adb. Po wywołaniu tego mechanizmu przywracanie systemu uruchamia jego własną wersję mini
demona adbd, by umożliwić adb na komputerze połączonym z hostem adbd. Ta miniatura
obsługuje tylko jedno polecenie:
adb sideload filename
. Nazwany plik jest wysyłany z hosta na urządzenie, które następnie weryfikuje i ocenia instaluje ją tak samo, jakby była przechowywana w pamięci lokalnej.
Kilka zastrzeżeń:
- Obsługiwany jest tylko transport przez USB.
-
Jeśli do odzyskiwania system działa normalnie (zwykle prawdziwe jest w przypadku kompilacji „userdebug” i „eng”,
zostanie wyłączone, gdy urządzenie jest w trybie pobierania z innego urządzenia adb, i zostanie ponownie uruchomione, gdy adb
instalowanie aplikacji z innego urządzenia zakończyło odebranie pakietu. W trybie adb adb nie pojawiają się polecenia adb inne
niż
sideload
praca (logcat
,reboot
,push
,pull
,shell
itd.). -
Na urządzeniu nie można wyłączyć trybu pobierania z innego urządzenia. Aby przerwać proces, możesz wysłać
/dev/null
(lub cokolwiek, co nie jest prawidłowym pakietem) jako pakietu, urządzenie nie może go zweryfikować i zatrzymać procedury instalacji. Interfejs RecoveryUI metodaCheckKey()
implementacji będzie nadal wywoływana dla naciśnięć klawiszy, możesz więc podać sekwencję klawiszy, która uruchamia urządzenie ponownie i działa w trybie wczytywania z innego urządzenia adb.