Kod na urządzeniu

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();
}

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.

obraz wyświetlany podczas błędu OTA

Rysunek 1. icon_error.png

obraz wyświetlany podczas instalacji OTA

Rysunek 2. icon_installing.png

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:

obraz wyświetlany podczas instalacji OTA

Rysunek 3. icon_installing.png

obraz wyświetlany jako pierwszy
nakładka

Rysunek 4. icon-installing_overlay01.png

obraz wyświetlany jako 7.
nakładka

Rysunek 5. icon_installing_overlay07.png

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:

obraz złożony
instalacja plus pierwsza nakładka

Rysunek 6. Instalowanie ramki animacji 1 (icon_installing.png + ikona_instalacji_overlay01.png)

obraz złożony
instalacja i siódma nakładka

Rysunek 7. Instalowanie ramki animacji 7 (icon_installing.png + ikona_instalacji_overlay07.png)

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:

obraz tekstu odzyskiwania

Rysunek 8. Zlokalizowany tekst wiadomości dotyczących odzyskiwania

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:

pusty pasek postępu

Rysunek 9. progress_empty.png

pełny pasek postępu

Rysunek 10. progress_fill.png

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:

pasek postępu na poziomie 1%

Rysunek 11. Pasek postępu na poziomie 1%>

pasek postępu ustawiony na 10%

Rysunek 12. Pasek postępu na poziomie 10%

pasek postępu na poziomie 50%

Rysunek 13. Pasek postępu na poziomie 50%

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 metoda CheckKey() 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.