Pembaruan Sistem A/B (Seamless)

Pembaruan sistem A/B, juga dikenal sebagai pembaruan tanpa batas, memastikan sistem booting yang dapat diterapkan tetap berada di disk selama pembaruan over-the-air (OTA) . Pendekatan ini mengurangi kemungkinan perangkat tidak aktif setelah pembaruan, yang berarti lebih sedikit penggantian perangkat dan reflash perangkat di pusat perbaikan dan garansi. Sistem operasi kelas komersial lainnya seperti ChromeOS juga berhasil menggunakan pembaruan A/B.

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

Pembaruan sistem A/B memberikan manfaat berikut:

  • Pembaruan OTA dapat terjadi saat sistem sedang berjalan, tanpa mengganggu pengguna. Pengguna dapat terus menggunakan perangkat mereka selama OTA—satu-satunya waktu henti selama pembaruan adalah saat perangkat melakukan boot ulang ke partisi disk yang diperbarui.
  • Setelah pembaruan, reboot tidak lebih lama dari reboot biasa.
  • Jika OTA gagal diterapkan (misalnya, karena flash yang buruk), pengguna tidak akan terpengaruh. Pengguna akan terus menjalankan OS lama, dan klien bebas mencoba kembali pembaruan.
  • Jika pembaruan OTA diterapkan tetapi gagal untuk boot, perangkat akan reboot kembali ke partisi lama dan tetap dapat digunakan. Klien bebas untuk mencoba kembali pembaruan.
  • Kesalahan apa pun (seperti kesalahan I/O) hanya memengaruhi kumpulan 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 pengalaman pengguna.
  • Pembaruan dapat dialirkan ke perangkat A/B, menghilangkan kebutuhan untuk mengunduh paket sebelum menginstalnya. Streaming berarti pengguna tidak perlu memiliki ruang kosong yang cukup untuk menyimpan paket pembaruan di /data atau /cache .
  • Partisi cache tidak lagi digunakan untuk menyimpan paket pembaruan OTA, jadi tidak perlu memastikan bahwa partisi cache cukup besar untuk pembaruan di masa mendatang.
  • dm-verity menjamin perangkat akan mem-boot gambar yang tidak rusak. Jika perangkat tidak bisa boot karena masalah OTA atau dm-verity yang buruk, perangkat dapat melakukan boot ulang ke image lama. ( Boot Terverifikasi Android tidak memerlukan pembaruan A/B.)

Tentang pembaruan sistem A/B

Pembaruan A/B memerlukan perubahan pada klien dan sistem. Server paket OTA, bagaimanapun, seharusnya tidak memerlukan perubahan: paket pembaruan masih disajikan melalui HTTPS. Untuk perangkat yang menggunakan infrastruktur OTA Google, perubahan sistem semuanya 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 klien mereka sendiri.

Untuk OEM yang memasok klien mereka sendiri, klien perlu:

  • Putuskan kapan harus melakukan pembaruan. Karena pembaruan A/B terjadi di latar belakang, pembaruan tersebut tidak lagi dimulai oleh pengguna. Untuk menghindari mengganggu pengguna, sebaiknya pembaruan dijadwalkan saat perangkat dalam mode pemeliharaan tidak aktif, seperti semalaman, dan di Wi-Fi. Namun, klien Anda dapat menggunakan heuristik apa pun yang Anda inginkan.
  • Periksa dengan server paket OTA Anda dan tentukan apakah pembaruan tersedia. Ini sebagian besar harus sama dengan kode klien Anda yang ada, kecuali bahwa Anda ingin memberi sinyal bahwa perangkat mendukung A/B. (Klien Google juga menyertakan tombol Periksa sekarang bagi pengguna untuk memeriksa pembaruan terbaru.)
  • Panggil update_engine dengan URL HTTPS untuk paket pembaruan Anda, dengan asumsi tersedia. update_engine akan memperbarui blok mentah pada partisi yang saat ini tidak digunakan saat mengalirkan paket pembaruan.
  • Laporkan keberhasilan atau kegagalan penginstalan ke server Anda, berdasarkan kode hasil update_engine . Jika pembaruan berhasil diterapkan, update_engine akan memberi tahu bootloader untuk boot ke OS baru pada reboot berikutnya. Bootloader akan mundur ke OS lama jika OS baru gagal untuk boot, jadi tidak ada pekerjaan yang diperlukan dari klien. Jika pembaruan gagal, klien perlu memutuskan kapan (dan apakah) akan mencoba lagi, berdasarkan kode kesalahan terperinci. Misalnya, klien yang baik dapat mengenali bahwa sebagian ("diff") paket OTA gagal dan mencoba paket OTA lengkap sebagai gantinya.

Secara opsional, klien dapat:

  • Tampilkan pemberitahuan yang meminta pengguna untuk melakukan boot ulang. Jika Anda ingin menerapkan kebijakan di mana pengguna didorong untuk memperbarui secara rutin, maka pemberitahuan ini dapat ditambahkan ke klien Anda. Jika klien tidak meminta pengguna, maka pengguna akan tetap mendapatkan pembaruan saat mereka melakukan boot ulang. (Klien Google memiliki penundaan yang dapat dikonfigurasi per pembaruan.)
  • Tampilkan pemberitahuan yang memberi tahu pengguna apakah mereka boot ke versi OS baru atau apakah mereka diharapkan melakukannya tetapi kembali ke versi OS lama. (Klien Google biasanya tidak melakukan keduanya.)

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

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

Pemilihan partisi (slot)

Pembaruan sistem A/B menggunakan dua set partisi yang disebut sebagai slot (biasanya slot A dan slot B). Sistem berjalan dari slot saat ini sedangkan partisi di slot yang tidak digunakan tidak diakses oleh sistem yang sedang berjalan selama operasi normal. Pendekatan ini membuat pembaruan tahan kesalahan dengan menjaga slot yang tidak digunakan sebagai cadangan: Jika kesalahan terjadi selama atau segera setelah pembaruan, sistem dapat mengembalikan 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 pembaruan OTA (termasuk partisi yang hanya memiliki satu salinan).

Setiap slot memiliki atribut yang dapat di- boot yang menyatakan apakah slot tersebut berisi sistem yang benar dari mana perangkat dapat 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 slot saat ini, ada satu slot yang merupakan slot aktif (slot yang akan bootloader akan boot pada boot berikutnya) atau slot pilihan .

Setiap slot juga memiliki atribut sukses yang ditetapkan oleh ruang pengguna, yang hanya relevan jika slot juga dapat di-boot. Slot yang berhasil harus dapat mem-boot, menjalankan, dan memperbarui sendiri. Slot yang dapat di-boot yang tidak ditandai sebagai berhasil (setelah beberapa upaya dilakukan untuk mem-boot 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 segera sebelum upaya untuk mem-boot ke yang baru dan aktif). Detail spesifik dari antarmuka didefinisikan di boot_control.h .

Perbarui daemon mesin

Pembaruan sistem A/B menggunakan daemon latar belakang yang disebut update_engine untuk mempersiapkan sistem untuk boot ke versi baru yang diperbarui. Daemon ini dapat melakukan tindakan berikut:

  • Baca dari partisi A/B slot saat ini dan tulis 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 pasca-instal dari partisi baru setelah menulis semua partisi slot yang tidak digunakan, seperti yang diinstruksikan oleh paket OTA. (Untuk detailnya, lihat Pasca-instalasi ).

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

Perbarui sumber mesin

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

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

Perbarui log mesin

Untuk rilis Android 8.x dan yang lebih lama, log update_engine dapat ditemukan di logcat dan dalam laporan bug. Untuk membuat log update_engine tersedia di sistem file, tambal perubahan berikut ke dalam 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 bawah /data/misc/update_engine_log/ . Pengguna dengan ID grup log akan dapat mengakses log sistem file.

Interaksi bootloader

boot_control HAL digunakan oleh update_engine (dan mungkin daemon lain) untuk menginstruksikan bootloader dari mana boot. Contoh skenario umum dan status terkaitnya mencakup hal berikut:

  • Kasus normal : Sistem berjalan dari slotnya saat ini, baik slot A atau B. Sejauh ini belum ada pembaruan yang diterapkan. Slot sistem saat ini dapat di-boot, berhasil, dan slot aktif.
  • Pembaruan sedang berlangsung : Sistem dijalankan dari slot B, jadi 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. Reboot dalam keadaan ini harus melanjutkan boot dari slot B.
  • Pembaruan diterapkan, reboot tertunda : 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 beberapa upaya untuk boot dari slot A harus dilakukan oleh bootloader.
  • Sistem di-boot ulang ke pembaruan baru : Sistem berjalan dari slot A untuk pertama kalinya, slot B masih dapat di-boot dan berhasil sementara 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 pembaruan streaming

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

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

Tambalan ini diperlukan untuk mendukung pembaruan A/B streaming di Android 7.1 dan yang lebih baru baik menggunakan Layanan Seluler Google (GMS) atau klien pembaruan lainnya.

Kehidupan pembaruan A/B

Proses pembaruan dimulai ketika paket OTA (disebut dalam kode sebagai payload ) tersedia untuk diunduh. Kebijakan di perangkat dapat menunda unduhan dan aplikasi payload berdasarkan tingkat baterai, aktivitas pengguna, status pengisian daya, atau kebijakan lainnya. Selain itu, karena pembaruan berjalan di latar belakang, pengguna mungkin tidak mengetahui bahwa pembaruan sedang berlangsung. Semua ini berarti proses pembaruan dapat terganggu kapan saja karena kebijakan, reboot yang tidak terduga, atau tindakan pengguna.

Secara opsional, metadata dalam paket OTA itu sendiri menunjukkan pembaruan dapat dialirkan; paket yang sama juga dapat digunakan untuk instalasi non-streaming. Server dapat menggunakan metadata untuk memberi tahu klien bahwa itu streaming sehingga klien akan menyerahkan OTA ke update_engine dengan benar. Produsen perangkat dengan server dan klien mereka sendiri dapat mengaktifkan pembaruan streaming dengan memastikan server mengidentifikasi pembaruan sedang streaming (atau menganggap semua pembaruan streaming) dan klien membuat panggilan yang benar ke update_engine untuk streaming. Produsen dapat menggunakan fakta bahwa paket tersebut adalah varian streaming untuk mengirim tanda ke klien untuk memicu penyerahan ke sisi kerangka kerja sebagai streaming.

Setelah payload tersedia, proses pembaruan adalah sebagai berikut:

Melangkah Kegiatan
1 Slot saat ini (atau "slot sumber") ditandai sebagai berhasil (jika belum ditandai) dengan markBootSuccessful() .
2 Slot yang tidak digunakan (atau "slot target") ditandai sebagai tidak dapat di-boot dengan memanggil fungsi setSlotAsUnbootable() . Slot saat ini selalu ditandai sebagai berhasil di awal pembaruan untuk mencegah bootloader jatuh kembali ke slot yang tidak digunakan, yang akan segera memiliki data yang tidak valid. Jika sistem telah mencapai titik di mana ia dapat mulai menerapkan pembaruan, slot saat ini ditandai sebagai berhasil meskipun komponen utama lainnya rusak (seperti UI dalam loop macet) karena dimungkinkan untuk mendorong perangkat lunak baru untuk memperbaikinya. masalah.

Muatan pembaruan adalah gumpalan buram dengan instruksi untuk memperbarui ke versi baru. Muatan pembaruan terdiri dari berikut ini:
  • Metadata . Sebagian kecil dari muatan pembaruan, metadata berisi daftar operasi untuk menghasilkan dan memverifikasi versi baru pada slot target. Misalnya, sebuah operasi dapat mendekompresi gumpalan tertentu dan menulisnya ke blok tertentu di partisi target, atau membaca dari partisi sumber, menerapkan tambalan biner, dan menulis ke blok tertentu di partisi target.
  • Data tambahan . Sebagai bagian terbesar dari muatan pembaruan, data tambahan yang terkait dengan operasi terdiri dari gumpalan terkompresi atau patch biner dalam contoh ini.
3 Metadata muatan diunduh.
4 Untuk setiap operasi yang didefinisikan dalam metadata, secara berurutan, data terkait (jika ada) diunduh ke memori, operasi diterapkan, dan memori terkait dibuang.
5 Seluruh partisi dibaca ulang dan diverifikasi terhadap hash yang diharapkan.
6 Langkah pasca-instal (jika ada) dijalankan. Jika terjadi kesalahan selama pelaksanaan langkah apa pun, pembaruan gagal dan dicoba kembali dengan kemungkinan muatan yang berbeda. Jika semua langkah sejauh ini sudah berhasil maka update berhasil dan langkah terakhir dijalankan.
7 Slot yang tidak digunakan ditandai sebagai aktif dengan memanggil setActiveBootSlot() . Menandai slot yang tidak digunakan sebagai aktif tidak berarti itu akan menyelesaikan booting. Bootloader (atau sistem itu sendiri) dapat mengganti slot aktif kembali jika tidak membaca status sukses.
8 Pasca-instalasi (dijelaskan di bawah) melibatkan menjalankan program dari versi "pembaruan baru" saat masih berjalan di versi lama. Jika didefinisikan dalam paket OTA, langkah ini wajib dan program harus kembali dengan kode keluar 0 ; jika tidak, pembaruan gagal.
9 Setelah sistem berhasil melakukan booting cukup jauh ke dalam slot baru dan menyelesaikan pemeriksaan pasca-reboot, slot saat ini (sebelumnya "slot target") ditandai sebagai berhasil dengan memanggil markBootSuccessful() .

Pasca-instalasi

Untuk setiap partisi di mana langkah pasca-instal 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-instal didefinisikan sebagai usr/bin/postinstall di partisi sistem, partisi dari slot yang tidak digunakan ini akan dipasang di lokasi tetap (seperti /postinstall_mount ) dan /postinstall_mount/usr/bin/postinstall perintah /postinstall_mount/usr/bin/postinstall dijalankan.

Agar pasca-instalasi 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 terkompresi (yaitu SquashFS).
  • Pahami format program pasca pemasangan partisi baru . Jika menggunakan biner Executable and Linkable Format (ELF), itu harus kompatibel dengan kernel lama (misalnya program baru 64-bit yang berjalan pada kernel 32-bit lama jika arsitektur beralih dari build 32- ke 64-bit). Kecuali jika pemuat ( ld ) diinstruksikan untuk menggunakan jalur lain atau membangun biner statis, pustaka akan dimuat dari citra sistem lama dan bukan yang baru.

Misalnya, Anda dapat menggunakan skrip shell sebagai program pasca-instal yang ditafsirkan oleh biner shell sistem lama dengan tanda #! penanda di atas), lalu atur jalur pustaka dari lingkungan baru untuk menjalankan program pasca-instal biner yang lebih kompleks. Atau, Anda dapat menjalankan langkah pasca pemasangan dari partisi khusus yang lebih kecil untuk mengaktifkan format sistem file di partisi sistem utama agar diperbarui tanpa menimbulkan masalah kompatibilitas mundur atau pembaruan batu loncatan; ini akan memungkinkan pengguna untuk memperbarui langsung ke versi terbaru dari gambar pabrik.

Program pasca-instal baru dibatasi oleh kebijakan SELinux yang ditentukan dalam sistem lama. Dengan demikian, langkah pasca-instal cocok untuk melakukan tugas yang diperlukan oleh desain pada perangkat tertentu atau tugas upaya terbaik lainnya (yaitu memperbarui firmware atau bootloader berkemampuan A/B, menyiapkan salinan database untuk versi baru, dll. ). Langkah pasca-instal tidak cocok untuk perbaikan bug satu kali sebelum reboot yang memerlukan izin tak terduga.

Program pasca-instal yang dipilih berjalan dalam konteks postinstall pasca-instal. Semua file di partisi baru yang dipasang akan ditandai dengan postinstall_file , terlepas dari apa atributnya setelah mem-boot ulang ke sistem baru itu. Perubahan pada atribut SELinux di sistem baru tidak akan memengaruhi langkah pasca-instal. Jika program pasca-instal memerlukan izin tambahan, izin tersebut harus ditambahkan ke konteks pasca-instal.

Setelah reboot

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

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