Update sistem A/B (lancar)

Update sistem A/B lama, yang juga dikenal sebagai update lancar , memastikan sistem booting yang berfungsi tetap ada di disk selama update over-the-air (OTA). Pendekatan ini mengurangi kemungkinan perangkat tidak aktif setelah update, yang berarti lebih sedikit penggantian perangkat dan penginstalan ulang perangkat di pusat reparasi dan garansi. Sistem operasi tingkat komersial lainnya seperti ChromeOS juga berhasil menggunakan update A/B.

Untuk mengetahui informasi selengkapnya tentang update sistem A/B dan cara kerjanya, lihat Pemilihan partisi (slot).

Update sistem A/B memberikan manfaat berikut:

  • Update OTA dapat terjadi saat sistem sedang berjalan, tanpa mengganggu pengguna. Pengguna dapat terus menggunakan perangkat mereka selama OTA—satu-satunya waktu nonaktif selama update adalah saat perangkat dimulai ulang ke partisi disk yang diupdate.
  • Setelah update, mulai ulang tidak akan lebih lama dari mulai ulang biasa.
  • Jika OTA gagal diterapkan (misalnya, karena flash yang buruk), pengguna tidak akan terpengaruh. Pengguna akan terus menjalankan OS lama, dan klien bebas mencoba lagi update.
  • Jika update OTA diterapkan tetapi gagal melakukan booting, perangkat akan melakukan booting ulang ke partisi lama dan tetap dapat digunakan. Klien bebas mencoba lagi update.
  • Error apa pun (seperti error I/O) hanya memengaruhi set partisi yang tidak digunakan dan dapat dicoba lagi. Kesalahan seperti itu juga menjadi lebih kecil kemungkinannya karena beban I/O sengaja dibuat rendah untuk menghindari penurunan kualitas pengalaman pengguna.
  • Update dapat di-streaming ke perangkat A/B, sehingga tidak perlu mendownload paket sebelum menginstalnya. Streaming berarti pengguna tidak perlu memiliki ruang kosong yang cukup untuk menyimpan paket update di /data atau /cache.
  • Partisi cache tidak lagi digunakan untuk menyimpan paket update OTA, jadi tidak perlu memastikan bahwa partisi cache cukup besar untuk update mendatang.
  • dm-verity menjamin perangkat akan mem-boot image yang tidak rusak. Jika perangkat tidak melakukan booting karena masalah OTA atau dm-verity yang buruk, perangkat dapat melakukan booting ulang ke image lama. (Android Boot Terverifikasi tidak memerlukan update A/B.)

Tentang update sistem A/B

Update A/B memerlukan perubahan pada klien dan sistem. Namun, server paket OTA tidak memerlukan perubahan: paket update tetap ditayangkan melalui HTTPS. Untuk perangkat yang menggunakan infrastruktur OTA Google, semua perubahan sistem ada di AOSP, dan kode klien disediakan oleh layanan Google Play. OEM yang tidak menggunakan infrastruktur OTA Google akan dapat menggunakan kembali kode sistem AOSP, tetapi harus menyediakan kliennya sendiri.

Untuk OEM yang menyediakan kliennya sendiri, klien harus:

  • Tentukan kapan harus melakukan update. Karena update A/B terjadi di latar belakang, update tersebut tidak lagi dimulai oleh pengguna. Untuk menghindari gangguan pada pengguna, sebaiknya update dijadwalkan saat perangkat dalam mode pemeliharaan tidak ada aktivitas, seperti pada malam hari, dan terhubung ke Wi-Fi. Namun, klien Anda dapat menggunakan heuristik apa pun yang Anda inginkan.
  • Periksa server paket OTA Anda dan tentukan apakah update tersedia. Kode ini sebagian besar akan sama dengan kode klien yang ada, kecuali Anda harus memberi sinyal bahwa perangkat mendukung A/B. (Klien Google juga menyertakan tombol Periksa sekarang agar pengguna dapat memeriksa update terbaru.)
  • Panggil update_engine dengan URL HTTPS untuk paket update Anda, dengan asumsi paket update tersedia. update_engine akan memperbarui blok mentah di partisi yang saat ini tidak digunakan saat melakukan streaming paket update.
  • Laporkan keberhasilan atau kegagalan penginstalan ke server Anda, berdasarkan kode hasil update_engine. Jika update berhasil diterapkan, update_engine akan memberi tahu bootloader untuk melakukan booting ke OS baru pada reboot berikutnya. Bootloader akan kembali ke OS lama jika OS baru gagal melakukan booting, sehingga tidak ada pekerjaan yang diperlukan dari klien. Jika update gagal, klien perlu memutuskan kapan (dan apakah) akan mencoba lagi, berdasarkan kode error mendetail. Misalnya, klien yang baik dapat mengenali bahwa paket OTA parsial ("diff") gagal dan mencoba paket OTA lengkap.

Secara opsional, klien dapat:

  • Tampilkan notifikasi yang meminta pengguna untuk memulai ulang. Jika Anda ingin menerapkan kebijakan yang mendorong pengguna untuk melakukan update secara rutin, notifikasi ini dapat ditambahkan ke klien Anda. Jika klien tidak meminta pengguna, pengguna akan mendapatkan update saat mereka melakukan reboot lain kali. (Klien Google memiliki penundaan yang dapat dikonfigurasi per update.)
  • Menampilkan notifikasi yang memberi tahu pengguna apakah mereka melakukan booting ke versi OS baru atau apakah mereka diharapkan melakukannya, tetapi kembali ke versi OS lama. (Klien Google biasanya tidak melakukannya.)

Di sisi sistem, update sistem A/B memengaruhi hal berikut:

  • Pemilihan partisi (slot), daemon update_engine, dan interaksi bootloader (dijelaskan di bawah)
  • Proses build dan pembuatan paket update OTA (dijelaskan dalam Menerapkan Update A/B)

Pemilihan partisi (slot)

Update sistem A/B menggunakan dua set partisi yang disebut sebagai slot (biasanya slot A dan slot B). Sistem berjalan dari slot saat ini sementara partisi di slot yang tidak digunakan tidak diakses oleh sistem yang sedang berjalan selama operasi normal. Pendekatan ini membuat update tahan terhadap kesalahan dengan menyimpan slot yang tidak digunakan sebagai pengganti: Jika terjadi error selama atau segera setelah update, sistem dapat melakukan rollback ke slot lama dan terus memiliki sistem yang berfungsi. Untuk mencapai tujuan ini, tidak ada partisi yang digunakan oleh slot saat ini yang harus diperbarui sebagai bagian dari update OTA (termasuk partisi yang hanya memiliki satu salinan).

Setiap slot memiliki atribut dapat di-boot yang menyatakan apakah slot berisi sistem yang benar yang dapat digunakan perangkat untuk melakukan booting. Slot saat ini dapat di-boot saat sistem sedang berjalan, tetapi slot lainnya mungkin memiliki versi sistem yang lama (masih benar), versi yang lebih baru, atau data yang tidak valid. Terlepas dari apa pun slot saat ini, ada satu slot yang merupakan slot aktif (yang akan digunakan bootloader untuk booting pada booting berikutnya) atau slot pilihan.

Setiap slot juga memiliki atribut berhasil yang ditetapkan oleh ruang pengguna, yang relevan hanya jika slot juga dapat di-boot. Slot yang berhasil harus dapat melakukan booting, menjalankan, dan mengupdate dirinya sendiri. Slot yang dapat di-boot yang tidak ditandai sebagai berhasil (setelah beberapa kali percobaan dilakukan untuk melakukan booting darinya) harus ditandai sebagai tidak dapat di-boot oleh bootloader, termasuk mengubah slot aktif ke slot lain yang dapat di-boot (biasanya ke slot yang berjalan tepat sebelum percobaan untuk melakukan booting ke slot aktif yang baru). Detail spesifik antarmuka ditentukan dalam boot_control.h.

Memperbarui daemon engine

Update sistem A/B menggunakan daemon latar belakang yang disebut update_engine untuk menyiapkan sistem agar melakukan booting ke versi baru yang telah diupdate. daemon ini dapat melakukan tindakan berikut:

  • Membaca dari partisi A/B slot saat ini dan menulis data apa pun ke partisi A/B slot yang tidak digunakan seperti yang diinstruksikan oleh paket OTA.
  • Panggil antarmuka boot_control dalam alur kerja yang telah ditentukan sebelumnya.
  • Jalankan program post-install dari partisi baru setelah menulis semua partisi slot yang tidak digunakan, seperti yang diinstruksikan oleh paket OTA. (Untuk mengetahui detailnya, lihat Pasca-penginstalan).

Karena daemon update_engine tidak terlibat dalam proses booting itu sendiri, daemon ini terbatas dalam hal yang dapat dilakukannya selama update oleh kebijakan dan fitur SELinux di slot saat ini (kebijakan dan fitur tersebut tidak dapat diupdate hingga sistem melakukan booting ke versi baru). Untuk mempertahankan sistem yang andal, proses update tidak boleh mengubah tabel partisi, konten partisi di slot saat ini, atau konten partisi non-A/B yang tidak dapat dihapus dengan reset ke setelan pabrik.

Memperbarui sumber mesin

Sumber update_engine terletak di system/update_engine. File dexopt OTA A/B dibagi antara installd dan pengelola paket:

Untuk contoh penggunaan, lihat /device/google/marlin/device-common.mk.

Log update engine

Untuk rilis Android 8.x dan yang lebih lama, log update_engine dapat ditemukan di logcat dan dalam laporan bug. Agar log update_engine tersedia di sistem file, terapkan perubahan berikut ke build Anda:

Perubahan ini menyimpan salinan log update_engine terbaru ke /data/misc/update_engine_log/update_engine.YEAR-TIME. Selain log saat ini, lima log terbaru disimpan di /data/misc/update_engine_log/. Pengguna dengan ID grup log akan dapat mengakses log sistem file.

Interaksi bootloader

HAL boot_control digunakan oleh update_engine (dan kemungkinan daemon lain) untuk menginstruksikan bootloader tentang apa yang harus di-boot. Contoh skenario umum dan status terkaitnya meliputi:

  • Kasus normal: Sistem berjalan dari slot saat ini, baik slot A maupun B. Sejauh ini, tidak ada update yang diterapkan. Slot sistem saat ini dapat di-boot, berhasil, dan merupakan slot aktif.
  • Update sedang berlangsung: Sistem berjalan dari slot B, sehingga slot B adalah slot yang dapat di-boot, berhasil, dan aktif. Slot A ditandai sebagai tidak dapat di-boot karena konten slot A sedang diperbarui, tetapi belum selesai. Mulai ulang dalam status ini akan terus melakukan booting dari slot B.
  • Update diterapkan, menunggu mulai ulang: Sistem berjalan dari slot B, slot B dapat di-boot dan berhasil, tetapi slot A ditandai sebagai aktif (dan oleh karena itu ditandai sebagai dapat di-boot). Slot A belum ditandai sebagai berhasil dan bootloader harus melakukan beberapa upaya untuk melakukan booting dari slot A.
  • Sistem di-reboot ke update baru: Sistem berjalan dari slot A untuk pertama kalinya, slot B masih dapat di-boot dan berhasil, sedangkan slot A hanya dapat di-boot, dan masih aktif tetapi tidak berhasil. Daemon ruang pengguna, update_verifier, harus menandai slot A sebagai berhasil setelah beberapa pemeriksaan dilakukan.

Dukungan update streaming

Perangkat pengguna tidak selalu memiliki cukup ruang di /data untuk mendownload paket update. Karena OEM maupun pengguna tidak ingin membuang-buang ruang di partisi /cache, beberapa pengguna tidak mendapatkan update karena perangkat tidak memiliki tempat untuk menyimpan paket update. Untuk mengatasi masalah ini, Android 8.0 menambahkan dukungan untuk update A/B streaming yang menulis blok langsung ke partisi B saat didownload, tanpa harus menyimpan blok di /data. Update A/B streaming hampir tidak memerlukan penyimpanan sementara dan hanya memerlukan penyimpanan yang cukup untuk sekitar 100 KiB metadata.

Untuk mengaktifkan update streaming di Android 7.1, pilih patch berikut:

Patch ini diperlukan untuk mendukung update A/B streaming di Android 7.1 dan yang lebih baru, baik menggunakan Layanan Seluler Google (GMS) maupun klien update lainnya.

Siklus proses update A/B

Proses update dimulai saat paket OTA (disebut dalam kode sebagai payload) tersedia untuk didownload. Kebijakan di perangkat dapat menunda download dan penerapan payload berdasarkan tingkat baterai, aktivitas pengguna, status pengisian daya, atau kebijakan lainnya. Selain itu, karena update berjalan di latar belakang, pengguna mungkin tidak tahu bahwa update sedang berlangsung. Semua ini berarti proses update dapat terganggu kapan saja karena kebijakan, mulai ulang yang tidak terduga, atau tindakan pengguna.

Secara opsional, metadata dalam paket OTA itu sendiri menunjukkan bahwa update dapat di-streaming; paket yang sama juga dapat digunakan untuk penginstalan non-streaming. Server dapat menggunakan metadata untuk memberi tahu klien bahwa server sedang melakukan streaming sehingga klien akan menyerahkan OTA ke update_engine dengan benar. Produsen perangkat dengan server dan klien sendiri dapat mengaktifkan update streaming dengan memastikan server mengidentifikasi bahwa update sedang di-streaming (atau menganggap semua update sedang di-streaming) dan klien melakukan panggilan yang benar ke update_engine untuk streaming. Produsen dapat menggunakan fakta bahwa paket tersebut adalah varian streaming untuk mengirimkan tanda ke klien guna memicu penyerahan ke sisi framework sebagai streaming.

Setelah payload tersedia, proses update adalah sebagai berikut:

Langkah Aktivitas
1 Slot saat ini (atau "slot sumber") ditandai sebagai berhasil (jika belum ditandai) dengan markBootSuccessful().
2 Slot yang tidak digunakan (atau "target slot") ditandai sebagai tidak dapat di-boot dengan memanggil fungsi setSlotAsUnbootable(). Slot saat ini selalu ditandai sebagai berhasil di awal update untuk mencegah bootloader melakukan penggantian ke slot yang tidak digunakan, yang akan segera memiliki data tidak valid. Jika sistem telah mencapai titik di mana sistem dapat mulai menerapkan update, slot saat ini ditandai sebagai berhasil meskipun komponen utama lainnya rusak (seperti UI dalam loop error) karena software baru dapat di-push untuk memperbaiki masalah ini.

Payload update adalah blob buram dengan petunjuk untuk mengupdate ke versi baru. Payload update terdiri dari hal berikut:
  • Metadata. Sebagian kecil payload update, metadata berisi daftar operasi untuk membuat dan memverifikasi versi baru di slot target. Misalnya, operasi dapat mendekompresi blob tertentu dan menuliskannya ke blok tertentu dalam partisi target, atau membaca dari partisi sumber, menerapkan patch biner, dan menulis ke blok tertentu dalam partisi target.
  • Data tambahan. Sebagai sebagian besar payload update, data tambahan yang terkait dengan operasi terdiri dari blob terkompresi atau patch biner dalam contoh ini.
3 Metadata payload didownload.
4 Untuk setiap operasi yang ditentukan dalam metadata, secara berurutan, data terkait (jika ada) akan didownload ke memori, operasi diterapkan, dan memori terkait akan dihapus.
5 Seluruh partisi dibaca ulang dan diverifikasi terhadap hash yang diharapkan.
6 Langkah pasca-penginstalan (jika ada) dijalankan. Jika terjadi error selama eksekusi langkah apa pun, update akan gagal dan dicoba lagi dengan kemungkinan payload yang berbeda. Jika semua langkah sejauh ini berhasil, update akan berhasil dan langkah terakhir akan dieksekusi.
7 Slot yang tidak digunakan ditandai sebagai aktif dengan memanggil setActiveBootSlot(). Menandai slot yang tidak digunakan sebagai aktif tidak berarti slot tersebut akan menyelesaikan booting. Bootloader (atau sistem itu sendiri) dapat mengalihkan slot aktif kembali jika tidak membaca status yang berhasil.
8 Setelah penginstalan (dijelaskan di bawah), program akan dijalankan dari versi "update baru" saat masih berjalan di versi lama. Jika ditentukan dalam paket OTA, langkah ini wajib dan program harus ditampilkan dengan kode keluar 0; jika tidak, update akan gagal.
9 Setelah sistem berhasil melakukan booting yang cukup jauh ke slot baru dan menyelesaikan pemeriksaan setelah booting ulang, slot yang sekarang aktif (sebelumnya "slot target") ditandai sebagai berhasil dengan memanggil markBootSuccessful().

Pasca-penginstalan

Untuk setiap partisi tempat langkah pasca-penginstalan ditentukan, update_engine memasang partisi baru ke lokasi tertentu dan menjalankan program yang ditentukan dalam OTA relatif terhadap partisi yang dipasang. Misalnya, jika program pasca-penginstalan ditentukan sebagai usr/bin/postinstall di partisi sistem, partisi ini dari slot yang tidak digunakan akan di-mount di lokasi tetap (seperti /postinstall_mount) dan perintah /postinstall_mount/usr/bin/postinstall akan dieksekusi.

Agar pasca-penginstalan berhasil, kernel lama harus dapat:

  • Pasang format sistem file baru. Jenis sistem file tidak dapat diubah kecuali ada dukungan untuknya di kernel lama, termasuk detail seperti algoritma kompresi yang digunakan jika menggunakan sistem file yang dikompresi (yaitu SquashFS).
  • Pahami format program setelah penginstalan partisi baru. Jika menggunakan biner Executable and Linkable Format (ELF), biner tersebut harus kompatibel dengan kernel lama (misalnya, program baru 64-bit yang berjalan di kernel 32-bit lama jika arsitekturnya beralih dari build 32-bit ke 64-bit). Kecuali jika loader (ld) diinstruksikan untuk menggunakan jalur lain atau membuat biner statis, library akan dimuat dari image sistem lama, bukan yang baru.

Misalnya, Anda dapat menggunakan skrip shell sebagai program pasca-penginstalan yang ditafsirkan oleh biner shell sistem lama dengan penanda #! di bagian atas), lalu menyiapkan jalur pustaka dari lingkungan baru untuk menjalankan program pasca-penginstalan biner yang lebih kompleks. Atau, Anda dapat menjalankan langkah pasca-penginstalan dari partisi khusus yang lebih kecil untuk memungkinkan format sistem file di partisi sistem utama diperbarui tanpa menimbulkan masalah kompatibilitas mundur atau update perantara; hal ini akan memungkinkan pengguna mengupdate langsung ke versi terbaru dari image pabrikan.

Program pasca-penginstalan baru dibatasi oleh kebijakan SELinux yang ditentukan dalam sistem lama. Dengan demikian, langkah pasca-penginstalan cocok untuk melakukan tugas yang diperlukan oleh desain pada perangkat tertentu atau tugas upaya terbaik lainnya. Langkah pasca-penginstalan tidak cocok untuk perbaikan bug sekali pakai sebelum reboot yang memerlukan izin yang tidak terduga.

Program pasca-penginstalan yang dipilih berjalan di konteks SELinux postinstall. Semua file di partisi yang baru di-mount akan ditandai dengan postinstall_file, terlepas dari atributnya setelah melakukan booting ulang ke sistem baru tersebut. Perubahan pada atribut SELinux di sistem baru tidak akan memengaruhi langkah pasca-penginstalan. Jika program pasca-penginstalan memerlukan izin tambahan, izin tersebut harus ditambahkan ke konteks pasca-penginstalan.

Setelah mulai ulang

Setelah melakukan reboot, update_verifier akan memicu pemeriksaan integritas menggunakan dm-verity. Pemeriksaan ini dimulai sebelum zygote untuk menghindari layanan Java membuat perubahan yang tidak dapat diubah yang akan mencegah rollback yang aman. Selama proses ini, bootloader dan kernel juga dapat memicu reboot jika booting terverifikasi atau dm-verity mendeteksi kerusakan. Setelah pemeriksaan selesai, update_verifier menandai bahwa booting berhasil.

update_verifier hanya akan membaca blok yang tercantum dalam /data/ota_package/care_map.txt, yang disertakan dalam paket OTA A/B saat menggunakan kode AOSP. Klien update sistem Java, seperti GmsCore, mengekstrak care_map.txt, menyiapkan izin akses sebelum memulai ulang perangkat, dan menghapus file yang diekstrak setelah sistem berhasil melakukan booting ke versi baru.