Kode khusus perangkat

Sistem pemulihan menyertakan beberapa hook untuk memasukkan kode khusus perangkat sehingga OTA update juga dapat mengupdate bagian perangkat selain sistem Android (misalnya, baseband atau prosesor radio).

Bagian dan contoh berikut menyesuaikan perangkat tardis yang dihasilkan oleh yoyodyne.

Peta partisi

Pada Android 2.3, platform ini mendukung perangkat flash eMMc dan sistem file ext4 yang menjalankan di perangkat tersebut. Hal ini juga mendukung perangkat flash Memory Technology Device (MTD) dan yaffs2 sistem file dari rilis lama.

File peta partisi ditentukan oleh TARGET_Recovery_FSTAB; file ini digunakan oleh biner pemulihan dan alat pembuatan paket. Anda dapat menetapkan nama file peta di TARGET_RECOVERY_FSTAB di BoardConfig.mk.

Contoh file peta partisi mungkin terlihat seperti ini:

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

Dengan pengecualian /sdcard, yang bersifat opsional, semua titik pemasangan di contoh harus ditentukan (perangkat juga dapat menambahkan partisi ekstra). Ada lima organisasi dukungan jenis sistem file:

yaffs2
Sistem file yaffs2 di atas perangkat flash MTD. "perangkat" harus berupa nama partisi MTD dan harus muncul di /proc/mtd.
mtd
Partisi MTD mentah, digunakan untuk partisi yang dapat di-booting seperti booting dan pemulihan. MTD bukan terpasang, tetapi titik pemasangan digunakan sebagai kunci untuk menemukan partisi. "perangkat" harus berupa nama partisi MTD di /proc/mtd.
ext4
Sistem file ext4 di atas perangkat flash eMMc. "perangkat" harus berupa jalur perangkat blok.
emmc
Perangkat blok eMMc mentah, digunakan untuk partisi yang dapat di-booting seperti booting dan pemulihan. Mirip dengan tipe {i>mtd<i}, eMMc tidak pernah benar-benar dipasang, tetapi {i>string<i} titik pemasangan digunakan untuk menemukan perangkat di dalam tabel.
vfat
Sistem file FAT di atas perangkat blok, biasanya untuk penyimpanan eksternal seperti kartu SD. Tujuan {i>device<i} adalah perangkat blok; device2 adalah perangkat blok kedua yang coba dipasang oleh sistem jika pemasangan perangkat utama akan gagal (untuk kompatibilitas dengan kartu SD yang mungkin diformat dengan tabel partisi).

Semua partisi harus dipasang di direktori {i>root<i} (misalnya, nilai direktori pemasangan harus diawali dengan garis miring dan tidak memiliki garis miring lainnya). Batasan ini hanya berlaku untuk pemasangan sistem file dalam pemulihan; sistem utama bebas untuk memasangnya di mana saja. Direktori /boot, /recovery, dan /misc harus berupa jenis mentah (mtd atau emmc), sedangkan direktori /system, /data, /cache, dan /sdcard (jika tersedia) harus berupa jenis sistem file (yaffs2, ext4, atau vfat).

Mulai Android 3.0, file recovery.fstab mendapatkan isian opsional tambahan, opsi. Saat ini satu-satunya opsi yang ditentukan adalah panjang , yang memungkinkan Anda secara eksplisit menentukan panjang partisi. Panjang ini digunakan saat memformat ulang partisi (misalnya, untuk partisi data pengguna selama operasi penghapusan total data/reset ke setelan pabrik, atau untuk partisi sistem selama penginstalan paket OTA lengkap). Jika nilai panjangnya negatif, ukuran yang akan diformat diambil dengan menambahkan nilai {i>length<i} ke ukuran partisi yang sebenarnya. Sebagai instance, menyetel "length=-16384" berarti 16 ribu terakhir dari partisi tersebut tidak akan akan ditimpa ketika partisi itu diformat ulang. Hal ini mendukung fitur seperti enkripsi data, partisi {i>userdata<i} (di mana {i>metadata <i}enkripsi disimpan di akhir partisi yang tidak boleh ditimpa).

Catatan: Kolom device2 dan options bersifat opsional, sehingga ambiguitas dalam penguraian. Jika entri di kolom keempat pada baris diawali dengan ‘/' karakter, itu dianggap sebagai entri device2 ; jika entri tidak dimulai dengan '/' karakter, elemen tersebut dianggap sebagai kolom options.

Animasi boot

Produsen perangkat memiliki kemampuan untuk menyesuaikan animasi yang ditampilkan saat perangkat Android sedang melakukan booting. Untuk melakukannya, buat file {i> .zip<i} yang terorganisir dan terletak sesuai dengan spesifikasi di format animasibooting.

Sebagai perangkat Android Things, Anda dapat mengunggah file zip di konsol Android Things untuk menyertakan gambar dalam produk yang dipilih.

Catatan: Gambar ini harus memenuhi pedoman merek Android. Untuk pedoman brand, lihat bagian Android pada Pemasaran Partner Hub.

UI Pemulihan

Untuk mendukung perangkat dengan hardware yang tersedia yang berbeda (tombol fisik, LED, layar, dll.), Anda dapat menyesuaikan antarmuka pemulihan untuk menampilkan status dan mengakses fitur tersembunyi untuk setiap perangkat.

Tujuan Anda adalah membangun pustaka statis kecil dengan beberapa objek C++ untuk menyediakan fungsi khusus perangkat. File bootable/recovery/default_device.cpp digunakan secara default, dan menjadikan titik awal untuk menyalin saat menulis versi file ini untuk perangkat Anda.

Catatan: Anda mungkin melihat pesan yang bertuliskan No Command di sini. Untuk beralih teks, tahan tombol daya sambil menekan tombol naikkan volume. Jika perangkat Anda tidak memiliki kedua tombol, tekan lama tombol apa saja untuk beralih teks.

device/yoyodyne/tardis/recovery/recovery_ui.cpp
#include <linux/input.h>

#include "common.h"
#include "device.h"
#include "screen_ui.h"

Fungsi header dan item

Class Perangkat memerlukan fungsi untuk menampilkan header dan item yang muncul di kolom menu pemulihan. Header menjelaskan cara mengoperasikan menu (yaitu kontrol untuk mengubah/memilih item yang disoroti).

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

Catatan: Garis panjang terpotong (tidak digabungkan), jadi pertahankan lebar layar perangkat.

Sesuaikan CheckKey

Berikutnya, tentukan implementasi RecoveryUI perangkat Anda. Contoh ini mengasumsikan tardis memiliki layar, jadi Anda dapat mewarisi dari Implementasi ScreenRecoveryUI (lihat petunjuk untuk perangkat tanpa layar.) Satu-satunya fungsi untuk menyesuaikan dari ScreenRecoveryUI adalah CheckKey(), yang melakukan penanganan kunci asinkron:

class TardisUI : public ScreenRecoveryUI {
  public:
    virtual KeyAction CheckKey(int key) {
        if (key == KEY_HOME) {
            return TOGGLE;
        }
        return ENQUEUE;
    }
};

Konstanta KEY

Konstanta KEY_* ditentukan di linux/input.h. CheckKey() sama dengan dipanggil apa pun yang terjadi selama proses pemulihan: ketika menu dimatikan, ketika aktif, selama instalasi paket, selama penghapusan data pengguna, dll. Aplikasi ini dapat mengembalikan satu dari empat konstanta:

  • GANTI. Mengaktifkan atau menonaktifkan tampilan menu dan/atau log teks
  • BOOT ULANG. Segera reboot perangkat
  • Abaikan. Abaikan penekanan tombol ini
  • ANTREAN. Mengantrekan penekanan tombol ini untuk digunakan secara sinkron (yaitu, oleh pemulihan sistem menu jika layar diaktifkan)

CheckKey() dipanggil setiap kali peristiwa key-down diikuti dengan peristiwa key-up untuk kunci yang sama. (Urutan kejadian A-bawah B-down B-up A-up hanya menghasilkan CheckKey(B) dipanggil.) CheckKey() dapat menelepon IsKeyPressed(), untuk mengetahui apakah kunci lain ditahan. (Dalam contoh di atas urutan peristiwa tombol, jika CheckKey(B) memanggil IsKeyPressed(A) akan menghasilkan nilai benar).

CheckKey() dapat mempertahankan status di class-nya; hal ini berguna untuk mendeteksi urutan huruf yang sama. Contoh ini menunjukkan penyiapan yang sedikit lebih kompleks: tampilan dialihkan oleh tahan daya dan menekan volume-naik, dan perangkat dapat segera dimulai ulang dengan menekan tombol daya lima kali berturut-turut (tanpa tombol intervensi lainnya):

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

UI Pemulihan Layar

Saat menggunakan gambar Anda sendiri (ikon error, animasi penginstalan, status progres) dengan ScreenRecoveryUI, Anda dapat menetapkan variabel animation_fps untuk mengontrol kecepatan dalam {i>frame per detik <i}(FPS) animasi.

Catatan: Skrip interlace-frames.py saat ini memungkinkan Anda menyimpan informasi animation_fps dalam gambar itu sendiri. Di versi sebelumnya Android harus menyetel animation_fps sendiri.

Untuk menetapkan variabel animation_fps, ganti Fungsi ScreenRecoveryUI::Init() di subclass Anda. Tetapkan nilai, lalu panggil metode parent Init() untuk menyelesaikan inisialisasi. Nilai default (20 FPS) sesuai dengan {i> image<i} pemulihan {i>default<i}; saat menggunakan gambar ini, Anda tidak perlu menyediakan fungsi Init(). Untuk mengetahui detail tentang gambar, lihat Gambar UI Pemulihan.

Class perangkat

Setelah Anda memiliki implementasi RecoveryUI, tentukan kelas perangkat Anda (disubkelaskan dari class Perangkat bawaan). Tindakan ini akan membuat satu instance class UI Anda dan menampilkannya dari fungsi GetUI():

class TardisDevice : public Device {
  private:
    TardisUI* ui;

  public:
    TardisDevice() :
        ui(new TardisUI) {
    }

    RecoveryUI* GetUI() { return ui; }

MemulaiPemulihan

Metode StartRecovery() dipanggil pada awal pemulihan, setelah UI memiliki telah diinisialisasi dan setelah argumen diuraikan, tetapi sebelum tindakan apa pun yang diambil. Implementasi default ini tidak melakukan apa pun, jadi Anda tidak perlu menyediakannya di subclass jika Anda tidak perlu melakukan apa pun:

   void StartRecovery() {
       // ... do something tardis-specific here, if needed ....
    }

Menyediakan dan mengelola menu pemulihan

Sistem memanggil dua metode untuk mendapatkan daftar baris header dan daftar item. Di sini , ia akan mengembalikan array statis yang ditentukan di bagian atas file:

const char* const* GetMenuHeaders() { return HEADERS; }
const char* const* GetMenuItems() { return ITEMS; }

{i>HandleMenuKey<i}

Selanjutnya, sediakan fungsi HandleMenuKey(), yang memerlukan penekanan tombol dan visibilitas menu, dan memutuskan tindakan yang akan diambil:

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

Metode ini mengambil kode kunci (yang sebelumnya telah diproses dan diantrekan oleh CheckKey() objek UI), dan status log menu/teks saat ini visibilitas tinggi. Nilai hasil berupa bilangan bulat. Jika nilainya 0 atau lebih tinggi, nilai tersebut dianggap sebagai posisi item menu, yang segera dipanggil (lihat InvokeMenuItem() di bawah). Jika tidak, parameter tersebut bisa berupa salah satu dari berikut konstanta yang telah ditentukan sebelumnya:

  • kHighlightUp. Memindahkan sorotan menu ke item sebelumnya
  • kHighlightDown. Memindahkan sorotan menu ke item berikutnya
  • kInvokeItem. Memanggil item yang sedang disorot
  • kNoAction. Tidak melakukan apa-apa dengan penekanan tombol ini

Seperti yang tersirat oleh argumen yang terlihat, HandleMenuKey() dipanggil meskipun menu tidak terlihat. Tidak seperti CheckKey(), fungsi ini tidak dipanggil saat pemulihan sedang berlangsung sesuatu seperti menghapus data atau menginstal paket. Fungsi ini hanya dipanggil ketika pemulihan sedang tidak ada aktivitas dan menunggu input.

Mekanisme trackball

Jika perangkat Anda memiliki mekanisme input seperti trackball (menghasilkan peristiwa input dengan jenis EV_REL dan kode REL_Y), pemulihan mensintesis tombol KEY_UP dan KEY_DOWN setiap kali perangkat input seperti trackball melaporkan gerakan di sumbu Y. Yang perlu Anda lakukan adalah memetakan KEY_UP dan KEY_DOWN ke tindakan menu. Pemetaan ini tidak terjadi untuk CheckKey(), sehingga Anda tidak dapat menggunakan gerakan trackball sebagai pemicu untuk memulai ulang atau mengalihkan layar.

Tombol pengubah

Untuk memeriksa kunci yang ditahan sebagai pengubah, panggil metode IsKeyPressed() objek UI Anda sendiri. Misalnya, pada sebagian perangkat yang menekan Alt-W dalam pemulihan akan memulai menghapus total data, terlepas dari apakah menu dapat terlihat atau tidak. YOu dapat mengimplementasikan seperti ini:

   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
        }
        ...
    }

Catatan: Jika visible adalah salah, tidak masuk akal untuk menampilkan spesial nilai yang memanipulasi menu (memindahkan sorotan, memanggil item yang disorot) karena pengguna tidak dapat melihat tanda. Namun, Anda dapat menampilkan nilai tersebut jika diinginkan.

InvokeMenuItem

Selanjutnya, sediakan metode InvokeMenuItem() yang memetakan posisi bilangan bulat dalam array item yang ditampilkan oleh GetMenuItems() untuk tindakan. Untuk array item dalam contoh tardis, gunakan:

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

Metode ini dapat menampilkan anggota enum BuiltinAction untuk memberi tahu sistem agar mengambil (atau anggota NO_ACTION jika Anda ingin sistem tidak melakukan apa pun). Ini adalah tempat untuk menyediakan fungsi pemulihan tambahan di luar apa yang ada dalam sistem: Menambahkan item di dalamnya menu Anda, jalankan di sini ketika item menu itu dipanggil, dan kembalikan NO_ACTION sehingga sistem tidak melakukan apa pun.

BuiltinAction berisi nilai berikut:

  • TIDAK_TINDAKAN. Tidak melakukan apa pun.
  • BOOT ULANG. Keluar dari pemulihan dan mulai ulang perangkat seperti biasa.
  • APPLY_EXT, APPLY_CACHE, APPLY_ADB_SIDELOAD. Menginstal paket pembaruan dari berbagai tempat. Untuk mengetahui detailnya, lihat Sideload.
  • WIPE_CACHE. Format ulang partisi cache saja. Konfirmasi tidak diperlukan karena hal ini relatif tidak berbahaya.
  • WIPE_DATA. Memformat ulang partisi cache dan data pengguna, yang juga dikenal sebagai data pabrik {i>reset<i}. Pengguna diminta untuk mengonfirmasi tindakan ini sebelum melanjutkan.

Metode terakhir, WipeData(), bersifat opsional dan dipanggil setiap kali penghapusan total data dimulai (baik dari pemulihan melalui menu atau ketika pengguna telah memilih untuk melakukan reset ke setelan pabrik dari sistem utama). Metode ini dipanggil sebelum data pengguna dan cache partisi akan dihapus. Jika perangkat Anda menyimpan data pengguna di mana pun selain kedua hal tersebut partisi, Anda harus menghapusnya di sini. Anda harus mengembalikan 0 untuk menunjukkan keberhasilan dan lainnya jika gagal, meskipun saat ini nilai yang ditampilkan diabaikan. Data pengguna dan cache partisi akan dihapus, baik Anda kembali berhasil atau gagal.

   int WipeData() {
       // ... do something tardis-specific here, if needed ....
       return 0;
    }

Buat perangkat

Terakhir, sertakan beberapa boilerplate di akhir file recovery_ui.cpp untuk Fungsi make_device() yang membuat dan menampilkan instance class Perangkat:

class TardisDevice : public Device {
   // ... all the above methods ...
};

Device* make_device() {
    return new TardisDevice();
}

Setelah menyelesaikan file recovery_ui.cpp, buat dan tautkan ke pemulihan di perangkat Anda. Di beberapa Android.mk, buat library statis yang hanya berisi file C++ ini:

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)

Kemudian, dalam konfigurasi board untuk perangkat ini, tetapkan library statis sebagai nilai TARGET_RECOVERY_UI_LIB.

device/yoyodyne/tardis/BoardConfig.mk
 [...]

# device-specific extensions to the recovery UI
TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis

Gambar UI pemulihan

Antarmuka pengguna pemulihan terdiri dari gambar. Idealnya, pengguna tidak pernah berinteraksi dengan UI: Selama pembaruan normal, ponsel melakukan {i> recovery<i}, mengisi bilah kemajuan instalasi, dan melakukan {i>booting<i} kembali ke sistem baru tanpa input dari pengguna. Jika sistem masalah pembaruan, satu-satunya tindakan pengguna yang dapat dilakukan adalah menghubungi layanan pelanggan.

Antarmuka khusus gambar meniadakan kebutuhan pelokalan. Namun, pada Android 5.0 dapat menampilkan string teks (mis. "Menginstal update sistem...") bersama gambar. Untuk mengetahui detailnya, lihat Teks pemulihan yang dilokalkan.

Android 5.0 dan yang lebih baru

UI pemulihan Android 5.0 dan yang lebih baru menggunakan dua gambar utama: gambar error dan animasi penginstalan.

gambar ditampilkan selama error OTA

Gambar 1. icon_error.png

gambar yang ditampilkan selama penginstalan OTA

Gambar 2. icon_installing.png

Animasi instalasi direpresentasikan sebagai satu gambar PNG dengan berbagai {i>frame<i} animasi yang bertautan oleh baris (itulah sebabnya Gambar 2 tampak diciutkan). Misalnya, untuk Animasi tujuh bingkai 200x200, buat satu gambar berukuran 200x1400 dengan bingkai pertama adalah baris 0, 7, 14, 21, ...; frame kedua adalah baris 1, 8, 15, 22, ...; dll. Gabungan gambar berisi potongan teks yang menunjukkan jumlah frame animasi dan jumlah frame per detik (FPS). Alat bootable/recovery/interlace-frames.py mengambil sekumpulan frame input dan menggabungkannya ke dalam gambar komposit yang diperlukan oleh pemulihan.

Gambar default tersedia dalam berbagai kepadatan dan berada di bootable/recovery/res-$DENSITY/images (mis., bootable/recovery/res-hdpi/images). Untuk menggunakan gambar statis selama instalasi, Anda hanya perlu menyediakan gambar icon_installing.png dan mengatur jumlah bingkai di animasi ke 0 (ikon error tidak dianimasikan; ikon selalu berupa gambar statis).

Android 4.x dan yang lebih lama

UI pemulihan Android 4.x dan versi yang lebih lama menggunakan gambar error (ditampilkan di atas) dan animasi menginstal plus beberapa gambar overlay:

gambar yang ditampilkan selama penginstalan OTA

Gambar 3. icon_installing.png

gambar ditampilkan sebagai yang pertama
iklan overlay

Gambar 4. icon-installing_overlay01.png

gambar ditampilkan sebagai gambar ketujuh
iklan overlay

Gambar 5. icon_installing_overlay07.png

Selama instalasi, tampilan pada layar dibuat dengan menggambar icon_installing.png gambar, lalu menggambar salah satu bingkai overlay di atasnya dengan offset yang tepat. Di sini, ditumpangkan untuk menyorot di mana overlay ditempatkan di atas gambar dasar:

gambar gabungan
instal plus overlay pertama

Gambar 6. Menginstal frame animasi 1 (icon_installing.png + icon_installing_overlay01.png)

gambar gabungan
instal plus overlay ketujuh

Gambar 7. Menginstal frame animasi 7 (icon_installing.png + icon_installing_overlay07.png)

Bingkai berikutnya ditampilkan dengan hanya menggambar gambar overlay berikutnya di atas apa yang sudah ada; gambar dasar tidak digambar ulang.

Jumlah frame dalam animasi, kecepatan yang diinginkan, serta offset x dan y overlay relatif terhadap basis diatur oleh variabel anggota class ScreenRecoveryUI. Saat menggunakan gambar kustom, bukan gambar default, ganti metode Init() di subclass untuk mengubah nilai ini bagi gambar kustom Anda (untuk detailnya, lihat ScreenRecoveryUI). Naskah bootable/recovery/make-overlay.py dapat membantu mengonversi kumpulan bingkai gambar ke "gambar dasar + gambar overlay" bentuk yang dibutuhkan oleh pemulihan, termasuk komputasi jumlah offset yang diperlukan.

Gambar default terletak di bootable/recovery/res/images. Untuk menggunakan gambar statis selama instalasi, Anda hanya perlu menyediakan gambar icon_installing.png dan mengatur jumlah frame dalam animasi ke 0 (ikon error tidak dianimasikan; selalu berupa gambar statis).

Teks pemulihan yang dilokalkan

Android 5.x menampilkan string teks (misalnya, "Menginstal update sistem...") beserta gambar. Bila sistem utama melakukan booting ke pemulihan, sistem ini akan meneruskan lokalitas pengguna saat ini sebagai opsi command line untuk pemulihan. Untuk setiap pesan yang ditampilkan, pemulihan mencakup gambar gabungan dengan string teks yang telah dipra-render untuk pesan tersebut di setiap lokalitas.

Gambar contoh string teks pemulihan:

gambar teks pemulihan

Gambar 8. Teks yang dilokalkan untuk pesan pemulihan

Teks pemulihan dapat menampilkan pesan berikut:

  • Menginstal pembaruan sistem...
  • Kesalahan!
  • Menghapus... (saat melakukan penghapusan total data/reset ke setelan pabrik)
  • Tidak ada perintah (saat pengguna melakukan booting ke pemulihan secara manual)

Aplikasi Android di bootable/recovery/tools/recovery_l10n/ merender pelokalan pada pesan dan membuat gambar gabungan. Untuk detail tentang cara menggunakan aplikasi ini, lihat komentar di bootable/recovery/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java.

Saat pengguna melakukan booting ke pemulihan secara manual, lokalitas mungkin tidak tersedia dan tidak ada teks yang ditampilkan. Jangan menjadikan pesan teks penting untuk proses pemulihan.

Catatan: Antarmuka tersembunyi yang menampilkan pesan log dan memungkinkan pengguna tindakan tertentu dari menu hanya tersedia dalam bahasa Inggris.

Bilah progres

Status progres dapat muncul di bawah gambar (atau animasi) utama. Status progres dibuat oleh yang menggabungkan dua gambar input, yang harus memiliki ukuran yang sama:

status progres kosong

Gambar 9. progress_empty.png

status progres lengkap

Gambar 10. progress_fill.png

Ujung kiri gambar isi ditampilkan di samping ujung kanan gambar kosong untuk membuat status progres. Posisi batas antara keduanya gambar diubah untuk menunjukkan kemajuannya. Misalnya, dengan pasangan gambar input di atas, tampilkan:

status progres di 1%

Gambar 11. Status progres di 1%>

status progres di 10%

Gambar 12. Status progres di 10%

status progres di 50%

Gambar 13. Status progres di 50%

Anda dapat menyediakan versi khusus perangkat untuk gambar tersebut dengan menempatkannya ke dalam (dalam contoh) device/yoyodyne/tardis/recovery/res/images kami. Nama file harus cocok dengan yang tercantum di atas; ketika sebuah file ditemukan di direktori tersebut, sistem build menggunakannya sebagai preferensi pada image default terkait. Hanya PNG dalam RGB atau Format RGBA dengan kedalaman warna 8-bit didukung.

Catatan: Di Android 5.x, jika lokalitas diketahui untuk pemulihan dan bahasa kanan-ke-kiri (RTL) (Arab, Ibrani, dll.), status progres diisi dari kanan ke kiri.

Perangkat tanpa layar

Tidak semua perangkat Android memiliki layar. Jika perangkat Anda adalah perangkat headless atau memiliki khusus audio saja, Anda mungkin perlu melakukan penyesuaian UI pemulihan yang lebih ekstensif. Sebagai gantinya pembuatan subclass ScreenRecoveryUI, buat subclass untuk RecoveryUI kelas induknya secara langsung.

RecoveryUI memiliki metode untuk menangani operasi UI tingkat rendah seperti "mengalihkan layar", "memperbarui status progres," "tampilkan menu," "mengubah pilihan menu," dll. Anda dapat mengganti ini untuk menyediakan antarmuka yang sesuai bagi perangkat Anda. Mungkin perangkat Anda memiliki LED di mana Anda bisa menggunakan beragam warna atau pola kedipan untuk menunjukkan keadaan, atau mungkin Anda bisa audio. (Mungkin Anda sama sekali tidak ingin mendukung menu atau mode "tampilan teks"; Anda dapat mencegah mereka mengaksesnya dengan CheckKey() dan Implementasi HandleMenuKey() yang tidak pernah mengaktifkan tampilan atau memilih menu yang bermanfaat. Dalam hal ini, banyak metode RecoveryUI yang perlu Anda sediakan bisa saja kosong stub.)

Lihat bootable/recovery/ui.h untuk deklarasi RecoveryUI guna melihat metode apa yang harus Anda dukung. RecoveryUI bersifat abstrak—beberapa metode murni virtual dan harus disediakan oleh Subclass—tetapi memang berisi kode untuk melakukan pemrosesan input kunci. Anda dapat menggantinya juga, jika perangkat Anda tidak memiliki kunci atau Anda ingin memprosesnya secara berbeda.

Updater

Anda bisa menggunakan kode khusus perangkat dalam penginstalan paket update dengan memberikan fungsi ekstensi Anda sendiri yang dapat dipanggil dari dalam skrip {i>updater<i} Anda. Berikut contohnya untuk perangkat tardis:

device/yoyodyne/tardis/recovery/recovery_updater.c
#include <stdlib.h>
#include <string.h>

#include "edify/expr.h"

Setiap fungsi ekstensi memiliki tanda tangan yang sama. Argumen adalah nama yang digunakan fungsi dipanggil, cookie State*, jumlah argumen yang masuk, dan array pointer Expr* yang mewakili argumen. Nilai yang ditampilkan adalah Value* yang baru dialokasikan.

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

Argumen Anda belum dievaluasi pada saat fungsi dipanggil— milik fungsi logika menentukan mana dari mereka yang dievaluasi dan berapa kali. Dengan demikian, Anda dapat menggunakan ekstensi fungsi untuk mengimplementasikan struktur kontrol Anda sendiri. Call Evaluate() untuk mengevaluasi argumen Expr* , yang menampilkan Value*. Jika Evaluate() mengembalikan NULL, Anda harus membebaskan sumber daya yang Anda simpan dan segera mengembalikan NULL (ini akan menyebarkan pembatalan stack edify). Jika tidak, Anda mengambil kepemilikan Nilai yang dikembalikan dan bertanggung jawab untuk memanggil FreeValue().

Misalnya fungsi memerlukan dua argumen: kunci bernilai string dan bernilai blob image. Anda dapat membaca argumen seperti ini:

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

Memeriksa NULL dan membebaskan argumen yang telah dievaluasi sebelumnya bisa membosankan untuk banyak argumen. Fungsi ReadValueArgs() dapat mempermudah hal ini. Alih-alih kode di atas, Anda bisa menulis ini:

   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() tidak melakukan pemeriksaan jenis, jadi Anda harus melakukannya di sini; lebih lebih mudah untuk melakukannya dengan satu pernyataan if dengan biaya menghasilkan jika gagal. Namun, ReadValueArgs() menangani evaluasi setiap argumen dan membebaskan semua argumen yang dievaluasi sebelumnya (serta menetapkan pesan error) jika ada evaluasi yang gagal. Anda dapat menggunakan ReadValueVarArgs() fungsi praktis untuk mengevaluasi angka variabel argumen (akan mengembalikan array Value*).

Setelah mengevaluasi argumen, lakukan fungsi fungsi tersebut:

   // 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 ...

Nilai yang ditampilkan harus berupa objek Value*; kepemilikan objek ini akan diteruskan ke pemanggil. Pemanggil mengambil kepemilikan data apa pun yang ditunjuk oleh panggilan ini Value*—khususnya anggota data.

Dalam contoh ini, Anda ingin menampilkan nilai benar atau salah untuk menunjukkan keberhasilan. Ingatlah bahwa string kosong adalah false dan semua string lainnya bernilai true. Anda harus melakukan malloc objek Value dengan salinan malloc dari string konstan yang akan ditampilkan, karena pemanggil akan free() keduanya. Jangan lupa untuk menghubungi FreeValue() di objek yang Anda dapatkan dengan mengevaluasi argumen.

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

Fungsi praktis StringValue() menggabungkan string ke dalam objek Value baru. Gunakan untuk menulis kode di atas secara lebih ringkas:

   FreeValue(key);
    FreeValue(image);

    return StringValue(strdup(successful ? "t" : ""));
}

Untuk mengaitkan fungsi ke edify interpreter, sediakan fungsi Register_foo dengan foo adalah nama library statis yang berisi pada kode ini. Panggil RegisterFunction() untuk mendaftarkan setiap fungsi ekstensi. Menurut khusus, beri nama fungsi khusus perangkat device.whatever untuk menghindari bentrok dengan fungsi bawaan yang ditambahkan di masa mendatang.

void Register_librecovery_updater_tardis() {
    RegisterFunction("tardis.reprogram", ReprogramTardisFn);
}

Sekarang Anda dapat mengonfigurasi makefile untuk membangun library statis dengan kode Anda. (Ini sama dengan makefile yang digunakan untuk menyesuaikan UI pemulihan di bagian sebelumnya; perangkat Anda mungkin memiliki keduanya library statis yang didefinisikan di sini.)

device/yoyodyne/tardis/recovery/Android.mk
include $(CLEAR_VARS)
LOCAL_SRC_FILES := recovery_updater.c
LOCAL_C_INCLUDES += bootable/recovery

Nama pustaka statis harus sama dengan nama Fungsi Register_libname yang ada di dalamnya.

LOCAL_MODULE := librecovery_updater_tardis
include $(BUILD_STATIC_LIBRARY)

Terakhir, konfigurasikan build pemulihan untuk mengakses koleksi Anda. Tambahkan koleksi Anda ke TARGET_RECOVERY_UPDATER_LIBS (yang mungkin berisi beberapa library; semuanya didaftarkan). Jika kode Anda bergantung pada library statis lain yang bukan ekstensi yang dibuat sendiri (yaitu, yang tidak memiliki fungsi Register_libname), Anda dapat mencantumkannya di TARGET_Recovery_UPDATER_EXTRA_LIBS untuk menautkannya ke updater tanpa memanggil (tidak ada). Misalnya, jika kode khusus perangkat Anda ingin menggunakan {i>zlib<i} untuk mendekompresi data, Anda akan menyertakan libz di sini.

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 +=

Skrip updater dalam paket OTA kini dapat memanggil fungsi Anda seperti yang lain. Untuk memprogram ulang di perangkat tardis Anda, skrip pembaruan mungkin berisi: tardis.reprogram("the-key", package_extract_file("tardis-image.dat")) . Hal ini menggunakan versi argumen tunggal dari fungsi bawaan package_extract_file(), yang menampilkan konten file yang diekstrak dari paket update sebagai blob untuk menghasilkan argumen kedua ke fungsi ekstensi yang baru.

Pembuatan paket OTA

Komponen terakhir adalah membuat alat pembuat paket OTA mengetahui tentang data khusus perangkat dan menghasilkan skrip updater yang menyertakan panggilan ke fungsi ekstensi Anda.

Pertama, buat sistem build mengetahui tentang blob data khusus perangkat. Dengan asumsi data Anda file berada di device/yoyodyne/tardis/tardis.dat, deklarasikan hal berikut di AndroidBoard.mk perangkat:

device/yoyodyne/tardis/AndroidBoard.mk
  [...]

$(call add-radio-file,tardis.dat)

Anda juga bisa memasukkannya ke dalam Android.mk, tetapi objek tersebut harus dilindungi oleh perangkat karena semua file Android.mk di hierarki dimuat, apa pun perangkat yang dibuat. (Jika hierarki Anda mencakup beberapa perangkat, Anda hanya perlu menambahkan file tardis.dat saat membangun perangkat 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

File ini disebut file radio karena alasan sejarah; mereka mungkin tidak ada hubungannya dengan radio perangkat (jika ada). Mereka hanyalah blob data buram yang disalin oleh sistem build ke dalam {i> .zip<i} file target yang digunakan oleh alat pembuat OTA. Saat Anda membangun, {i>tardis.dat<i} disimpan di target-files.zip sebagai RADIO/tardis.dat. Anda dapat memanggil add-radio-file beberapa kali untuk menambahkan file sebanyak yang Anda inginkan.

Modul Python

Untuk memperluas alat rilis, tulis modul Python (harus bernama releasetools.py) alat tersebut yang dapat dihubungi jika ada. Contoh:

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"));""")

Fungsi terpisah menangani kasus pembuatan paket OTA inkremental. Untuk ini misalnya, Anda perlu memprogram ulang tardis hanya ketika file tardis.dat telah berubah di antara dua build.

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"));""")

Fungsi modul

Anda dapat menyediakan fungsi berikut dalam modul (hanya terapkan fungsi yang Anda butuhkan).

FullOTA_Assertions()
Dipanggil menjelang awal pembuatan OTA penuh. Inilah tempat yang baik untuk memunculkan pernyataan tentang status perangkat saat ini. Jangan memunculkan perintah skrip yang membuat perubahan pada perangkat seluler.
FullOTA_InstallBegin()
Dipanggil setelah semua pernyataan tentang status perangkat berlalu, tetapi sebelum perubahan apa pun dilakukan. Anda dapat memberikan perintah untuk update khusus perangkat yang harus dijalankan sebelumnya hal lain pada perangkat telah diubah.
FullOTA_InstallEnd()
Dipanggil pada akhir pembuatan skrip, setelah perintah skrip untuk memperbarui {i>boot<i} dan partisi sistem telah dimunculkan. Anda juga dapat memberikan perintah tambahan untuk update untuk perangkat tertentu.
IncrementalOTA_Assertions()
Mirip dengan FullOTA_Assertions(), tetapi dipanggil saat membuat inkremental memperbarui paket.
IncrementalOTA_VerifyBegin()
Dipanggil setelah semua pernyataan tentang status perangkat diteruskan, tetapi sebelum perubahan apa pun dilakukan. Anda dapat memberikan perintah untuk update khusus perangkat yang harus dijalankan sebelum melakukan apa pun {i>else<i} pada perangkat telah diubah.
IncrementalOTA_VerifyEnd()
Dipanggil pada akhir fase verifikasi, ketika skrip telah selesai mengonfirmasi file yang akan disentuh memiliki konten awal yang diharapkan. Saat ini, tidak ada perangkat telah diubah. Anda juga dapat memunculkan kode untuk perangkat tambahan khusus verifikasi.
IncrementalOTA_InstallBegin()
Dipanggil setelah file yang akan di-patch telah diverifikasi memiliki sebelum, tetapi sebelum perubahan apa pun dibuat. Anda dapat memunculkan perintah untuk pembaruan khusus perangkat yang harus dijalankan sebelum hal lain pada perangkat diubah.
IncrementalOTA_InstallEnd()
Mirip dengan paket OTA lengkap, metode ini dipanggil di akhir skrip setelah perintah {i>script<i} untuk memperbarui partisi {i>boot<i} dan sistem telah dikeluarkan. Anda juga bisa memberikan perintah tambahan untuk update khusus perangkat.

Catatan: Jika perangkat kehilangan daya, penginstalan OTA dapat dimulai ulang dari memulai. Bersiaplah untuk menangani perangkat yang telah menjalankan perintah ini, seluruhnya atau sebagian.

Meneruskan fungsi ke objek info

Teruskan fungsi ke satu objek info yang berisi berbagai item berguna:

  • info.input_zip. (Khusus OTA lengkap) Objek zipfile.ZipFile untuk masukkan .zip file target.
  • info.source_zip. (Khusus OTA inkremental) Objek zipfile.ZipFile untuk file target-sumber .zip (build sudah ada di perangkat ketika paket inkremental sedang diinstal).
  • info.target_zip. (Khusus OTA inkremental) Objek zipfile.ZipFile untuk file target target .zip (build yang dimasukkan paket inkremental ke perangkat).
  • info.output_zip. Paket sedang dibuat; objek zipfile.ZipFile dibuka untuk menulis. Gunakan common.ZipWriteStr(info.output_zip, filename, data) untuk menambahkan file ke paket.
  • info.script. Objek skrip tempat Anda dapat menambahkan perintah. Telepon info.script.AppendExtra(script_text) untuk menghasilkan teks ke dalam skrip. Pastikan teks output diakhiri dengan titik koma agar tidak mengalami perintah yang ditampilkan setelah itu.

Untuk detail tentang objek info, lihat Dokumentasi Python Software Foundation untuk arsip ZIP.

Menentukan lokasi modul

Tentukan lokasi skrip releasetools.py perangkat Anda di file BoardConfig.mk file:

device/yoyodyne/tardis/BoardConfig.mk
 [...]

TARGET_RELEASETOOLS_EXTENSIONS := device/yoyodyne/tardis

Jika TARGET_RELEASETOOLS_EXTENSIONS tidak ditetapkan, setelan default adalah Direktori $(TARGET_DEVICE_DIR)/../common (device/yoyodyne/common dalam contoh ini). Sebaiknya tentukan lokasi skrip releasetools.py secara eksplisit. Saat membangun perangkat tardis, skrip releasetools.py disertakan dalam file target File .zip (META/releasetools.py ).

Saat Anda menjalankan alat rilis (img_from_target_files atau ota_from_target_files), skrip releasetools.py dalam .zip file target, jika yang ada, lebih disukai daripada yang berasal dari hierarki sumber Android. Anda juga dapat secara eksplisit tentukan jalur ke ekstensi khusus perangkat dengan -s (atau --device_specific), yang merupakan prioritas utama. Hal ini memungkinkan Anda untuk memperbaiki error dan mengubah ekstensi releasetools dan menerapkan perubahan tersebut ke file target.

Sekarang, saat Anda menjalankan ota_from_target_files, kode ini otomatis mengambil modul khusus perangkat dari file .zip target_files dan menggunakannya saat membuat OTA paket:

./build/make/tools/releasetools/ota_from_target_files \
    -i PREVIOUS-tardis-target_files.zip \
    dist_output/tardis-target_files.zip \
    incremental_ota_update.zip

Atau, Anda dapat menentukan ekstensi khusus perangkat saat Anda menjalankan 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

Catatan: Untuk daftar lengkap opsi, lihat ota_from_target_files komentar di build/make/tools/releasetools/ota_from_target_files.

Mekanisme sideload

Pemulihan memiliki mekanisme sideload untuk menginstal paket update secara manual tanpa mengunduhnya secara {i>over-the-air<i} oleh sistem utama. {i>Sideload<i} berguna untuk {i> debug<i} atau membuat perubahan pada perangkat di mana sistem utama tidak dapat di-{i>booting<i}.

Secara historis, {i>sideload<i} telah dilakukan melalui pemuatan paket dari kartu SD perangkat; inci pada perangkat non-{i>booting<i}, paket dapat ditempatkan ke kartu SD menggunakan komputer dan kemudian kartu SD yang dimasukkan ke dalam perangkat. Untuk mengakomodasi perangkat Android tanpa penyimpanan eksternal yang dapat dilepas, pemulihan mendukung dua mekanisme tambahan untuk sideload: memuat paket dari partisi cache, dan memuatnya melalui USB menggunakan adb.

Untuk memanggil setiap mekanisme sideload, metode Device::InvokeMenuItem() perangkat Anda dapat mengembalikan nilai BuiltinAction berikut:

  • APPLY_EXT. Melakukan sideload paket update dari penyimpanan eksternal ( /sdcard direktori). recovery.fstab Anda harus menentukan direktori pemasangan /sdcard . Ini adalah tidak dapat digunakan di perangkat yang mengemulasi kartu SD dengan symlink ke /data (atau beberapa mekanisme serupa). /data biasanya tidak dapat dipulihkan karena mungkin dienkripsi. UI pemulihan menampilkan menu file .zip di /sdcard dan memungkinkan pengguna untuk memilih satu.
  • APPLY_CACHE. Mirip dengan memuat paket dari /sdcard, hanya saja Direktori /cache (yang selalu tersedia untuk pemulihan) digunakan sebagai gantinya. Dari sistem reguler, /cache hanya dapat ditulis oleh pengguna berhak istimewa, dan jika perangkat tidak dapat di-{i>booting<i} maka direktori /cache tidak dapat ditulis ke sama sekali (yang menjadikan mekanisme ini utilitas terbatas).
  • APPLY_ADB_SIDELOAD. Memungkinkan pengguna mengirim paket ke perangkat melalui kabel USB dan alat pengembangan adb. Saat mekanisme ini dipanggil, pemulihan akan memulai versi {i>daemon<i} adbd agar adb komputer {i>host<i} yang terhubung dapat berbicara dengannya. Mini ini hanya mendukung satu perintah: adb sideload filename. File yang dinamai dikirim dari mesin {i>host<i} ke perangkat, yang kemudian memverifikasi dan menginstalnya seolah-olah telah berada di penyimpanan lokal.

Beberapa hal yang perlu diwaspadai:

  • Hanya transportasi USB yang didukung.
  • Jika pemulihan Anda menjalankan adbd secara normal (biasanya benar untuk userdebug dan build ing), hal itu akan dimatikan saat perangkat dalam mode sideload adb dan akan dimulai ulang saat adb {i>sideload<i} telah selesai menerima paket. Saat dalam mode sideload adb, tidak ada perintah adb lainnya dari sideload pekerjaan ( logcat, reboot, push, pull , shell, dll. semuanya gagal).
  • Anda tidak dapat keluar dari mode sideload adb di perangkat. Untuk membatalkan, Anda dapat mengirim /dev/null (atau apa pun yang bukan paket yang valid) sebagai paket, dan maka perangkat akan gagal untuk memverifikasinya dan menghentikan prosedur instalasi. RecoveryUI metode CheckKey() implementasi akan terus dipanggil untuk penekanan tombol, sehingga Anda dapat memberikan urutan tombol yang akan memulai ulang perangkat dan bekerja dalam mode sideload adb.