A/B (Sorunsuz) Sistem Güncellemeleri

Kesintisiz güncellemeler olarak da bilinen A/B sistem güncellemeleri, kablosuz (OTA) güncellemesi sırasında diskte çalışabilir bir önyükleme sisteminin kalmasını sağlar. Bu yaklaşım, bir güncellemeden sonra etkin olmayan bir cihaz olasılığını azaltır, bu da onarım ve garanti merkezlerinde daha az cihaz değişimi ve cihaz yeniden yanıp sönmesi anlamına gelir. ChromeOS gibi diğer ticari sınıf işletim sistemleri de A/B güncellemelerini başarıyla kullanır.

A/B sistem güncellemeleri ve nasıl çalıştıkları hakkında daha fazla bilgi için Bölüm seçimi (yuvalar) bölümüne bakın.

A/B sistem güncellemeleri aşağıdaki avantajları sağlar:

  • OTA güncellemeleri, sistem çalışırken kullanıcıyı kesintiye uğratmadan gerçekleşebilir. Kullanıcılar OTA sırasında cihazlarını kullanmaya devam edebilirler—bir güncelleme sırasındaki tek kesinti, cihazın güncellenmiş disk bölümünde yeniden başlatıldığı zamandır.
  • Güncellemeden sonra yeniden başlatma, normal yeniden başlatmadan daha uzun sürmez.
  • Bir OTA uygulanamazsa (örneğin, kötü bir flaş nedeniyle), kullanıcı etkilenmeyecektir. Kullanıcı eski işletim sistemini çalıştırmaya devam edecek ve istemci güncellemeyi yeniden denemekte serbesttir.
  • Bir OTA güncellemesi uygulanır ancak önyükleme başarısız olursa, cihaz eski bölüme yeniden başlar ve kullanılabilir durumda kalır. İstemci, güncellemeyi yeniden denemekte serbesttir.
  • Herhangi bir hata (G/Ç hataları gibi) yalnızca kullanılmayan bölüm kümesini etkiler ve yeniden denenebilir. G/Ç yükü, kullanıcı deneyiminin bozulmasını önlemek için kasıtlı olarak düşük olduğundan, bu tür hatalar da daha az olası hale gelir.
  • Güncellemeler A/B cihazlarına aktarılabilir, bu da paketi kurmadan önce indirme ihtiyacını ortadan kaldırır. Akış, kullanıcının güncelleme paketini /data veya /cache üzerinde depolamak için yeterli boş alana sahip olmasının gerekli olmadığı anlamına gelir.
  • Önbellek bölümü artık OTA güncelleme paketlerini depolamak için kullanılmamaktadır, bu nedenle önbellek bölümünün gelecekteki güncellemeler için yeterince büyük olduğundan emin olmanıza gerek yoktur.
  • dm-verity , bir aygıtın bozulmamış bir görüntüyü önyükleyeceğini garanti eder. Bir aygıt, kötü bir OTA veya dm-verity sorunu nedeniyle önyükleme yapmazsa, aygıt eski bir görüntüye yeniden başlayabilir. (Android Verified Boot , A/B güncellemeleri gerektirmez.)

A/B sistem güncellemeleri hakkında

A/B güncellemeleri, hem istemcide hem de sistemde değişiklik yapılmasını gerektirir. Ancak OTA paket sunucusu değişiklik gerektirmemelidir: güncelleme paketleri hala HTTPS üzerinden sunulur. Google'ın OTA altyapısını kullanan cihazlar için sistem değişikliklerinin tamamı AOSP'dedir ve istemci kodu Google Play hizmetleri tarafından sağlanmaktadır. Google'ın OTA altyapısını kullanmayan OEM'ler, AOSP sistem kodunu yeniden kullanabilecek ancak kendi istemcilerini sağlamaları gerekecek.

Kendi müşterisini tedarik eden OEM'ler için müşterinin şunları yapması gerekir:

  • Ne zaman güncelleme alacağınıza karar verin. A/B güncellemeleri arka planda gerçekleştiği için artık kullanıcı tarafından başlatılmazlar. Kullanıcıları rahatsız etmemek için güncellemelerin, cihaz gece gibi boşta bakım modundayken ve Wi-Fi üzerindeyken planlanması önerilir. Ancak, müşteriniz istediğiniz herhangi bir buluşsal yöntemi kullanabilir.
  • OTA paket sunucularınızı kontrol edin ve bir güncelleme olup olmadığını belirleyin. Bu, cihazın A/B'yi desteklediğini belirtmek istemeniz dışında, çoğunlukla mevcut istemci kodunuzla aynı olmalıdır. (Google'ın istemcisi ayrıca, kullanıcıların en son güncellemeyi kontrol etmeleri için bir Şimdi kontrol et düğmesi içerir.)
  • Mevcut olduğunu varsayarak güncelleme paketiniz için HTTPS URL'si ile update_engine arayın. update_engine , güncelleme paketini aktarırken, o anda kullanılmayan bölümdeki ham blokları güncelleyecektir.
  • update_engine sonuç koduna göre yükleme başarılarını veya hatalarını sunucularınıza bildirin. Güncelleme başarılı bir şekilde uygulanırsa update_engine , önyükleyiciye bir sonraki yeniden başlatmada yeni işletim sisteminde önyükleme yapmasını söyler. Yeni işletim sistemi önyükleme yapamazsa, önyükleyici eski işletim sistemine geri döner, bu nedenle istemcinin herhangi bir çalışması gerekmez. Güncelleme başarısız olursa, müşterinin ayrıntılı hata koduna göre ne zaman (ve tekrar deneyip denemeyeceğine) karar vermesi gerekir. Örneğin, iyi bir müşteri kısmi ("fark") bir OTA paketinin başarısız olduğunu anlayabilir ve bunun yerine tam bir OTA paketini deneyebilir.

İsteğe bağlı olarak, müşteri şunları yapabilir:

  • Kullanıcıdan yeniden başlatmasını isteyen bir bildirim göster. Kullanıcının rutin olarak güncelleme yapmasının teşvik edildiği bir politika uygulamak istiyorsanız, bu bildirim müşterinize eklenebilir. İstemci kullanıcılara sormazsa, kullanıcılar yine de yeniden başlattıklarında güncellemeyi alır. (Google'ın istemcisinin, güncelleme başına yapılandırılabilir bir gecikmesi vardır.)
  • Kullanıcılara yeni bir işletim sistemi sürümüne mi geçtiklerini veya bunu yapmalarının beklenip eski işletim sistemi sürümüne geri mi döndüklerini bildiren bir bildirim gösterin. (Google'ın müşterisi genellikle ikisini de yapmaz.)

Sistem tarafında, A/B sistem güncellemeleri aşağıdakileri etkiler:

  • Bölüm seçimi (yuvalar), update_engine arka plan programı ve önyükleyici etkileşimleri (aşağıda açıklanmıştır)
  • Derleme süreci ve OTA güncelleme paketi oluşturma ( A/B Güncellemelerini Uygulama bölümünde açıklanmıştır)

Bölüm seçimi (yuvalar)

A/B sistem güncellemeleri, yuva olarak adlandırılan iki bölüm kümesi kullanır (normalde yuva A ve yuva B). Normal çalışma sırasında, kullanılmayan yuvadaki bölümlere çalışan sistem tarafından erişilmezken sistem mevcut yuvadan çalışır. Bu yaklaşım, kullanılmayan yuvayı yedek olarak tutarak güncellemeleri hataya dayanıklı hale getirir: Bir güncelleme sırasında veya hemen sonrasında bir hata oluşursa, sistem eski yuvaya geri dönebilir ve çalışan bir sisteme sahip olmaya devam edebilir. Bu amaca ulaşmak için, geçerli yuva tarafından kullanılan hiçbir bölüm OTA güncellemesinin bir parçası olarak güncellenmemelidir (yalnızca bir kopyası bulunan bölümler dahil).

Her yuvanın, yuvanın aygıtın önyükleme yapabileceği doğru bir sistem içerip içermediğini belirten bir önyüklenebilir özniteliği vardır. Geçerli yuva, sistem çalışırken önyüklenebilir, ancak diğer yuvada sistemin eski (hala doğru) bir sürümü, daha yeni bir sürümü veya geçersiz veriler olabilir. Geçerli yuvanın ne olduğuna bakılmaksızın, etkin yuva (önyükleyicinin bir sonraki önyüklemede önyükleneceği yuva) veya tercih edilen yuva olan bir yuva vardır.

Her yuvanın ayrıca kullanıcı alanı tarafından belirlenen başarılı bir özelliği vardır; bu, yalnızca yuvanın da önyüklenebilir olması durumunda geçerlidir. Başarılı bir yuva, kendini başlatabilmeli, çalıştırabilmeli ve güncelleyebilmelidir. Başarılı olarak işaretlenmemiş bir önyüklenebilir yuva (birkaç önyükleme denemesinden sonra), etkin yuvanın başka bir önyüklenebilir yuvaya değiştirilmesi (normalde önyükleme denemesinden hemen önce çalışan yuvaya) dahil olmak üzere, önyükleyici tarafından ön yüklenemez olarak işaretlenmelidir. yeni, aktif olana). Arayüzün belirli ayrıntıları boot_control.h içinde tanımlanmıştır.

Motor arka plan programını güncelle

A/B sistem güncellemeleri, sistemi yeni, güncellenmiş bir sürüme önyüklemeye hazırlamak için update_engine adlı bir arka plan arka plan programı kullanır. Bu arka plan programı aşağıdaki eylemleri gerçekleştirebilir:

  • Geçerli yuva A/B bölümlerinden okuyun ve OTA paketi tarafından talimat verildiği şekilde kullanılmayan yuva A/B bölümlerine herhangi bir veri yazın.
  • Ön tanımlı bir iş akışında boot_control arabirimini çağırın.
  • Kullanılmayan tüm yuva bölümlerini OTA paketinde belirtildiği gibi yazdıktan sonra yeni bölümden bir yükleme sonrası programı çalıştırın. (Ayrıntılar için bkz. Kurulum sonrası ).

update_engine arka plan programı, önyükleme işleminin kendisinde yer almadığından, bir güncelleme sırasında yapabilecekleri, geçerli yuvadaki SELinux ilkeleri ve özellikleri tarafından sınırlandırılmıştır (bu tür ilkeler ve özellikler, sistem yeniden başlatılıncaya kadar güncellenemez). Yeni sürüm). Sağlam bir sistem sürdürmek için güncelleme işlemi , bölüm tablosunu, geçerli yuvadaki bölümlerin içeriğini veya fabrika ayarlarına sıfırlama ile silinemeyen A/B olmayan bölümlerin içeriğini değiştirmemelidir.

Motor kaynağını güncelle

update_engine kaynağı system/update_engine içinde bulunur. A/B OTA dexopt dosyaları, installd ve bir paket yöneticisi arasında bölünür:

Çalışan bir örnek için /device/google/marlin/device-common.mk bakın.

Motor günlüklerini güncelle

Android 8.x ve önceki sürümleri için update_engine günlükleri, logcat ve hata raporunda bulunabilir. update_engine günlüklerini dosya sisteminde kullanılabilir hale getirmek için aşağıdaki değişiklikleri derlemenize yamalayın:

Bu değişiklikler, en son update_engine günlüğünün bir kopyasını /data/misc/update_engine_log/update_engine. YEAR - TIME . Geçerli günlüğe ek olarak, en son beş günlük, /data/misc/update_engine_log/ altında kaydedilir. Günlük grubu kimliğine sahip kullanıcılar, dosya sistemi günlüklerine erişebilir.

Önyükleyici etkileşimleri

boot_control HAL, update_engine (ve muhtemelen diğer daemon'lar) tarafından, önyükleyiciye neyin önyükleneceğini bildirmek için kullanılır. Yaygın örnek senaryolar ve bunlarla ilişkili durumlar aşağıdakileri içerir:

  • Normal durum : Sistem, A veya B yuvası olan mevcut yuvasından çalışıyor. Şu ana kadar herhangi bir güncelleme uygulanmadı. Sistemin mevcut yuvası önyüklenebilir, başarılı ve etkin yuvadır.
  • Güncelleme devam ediyor : Sistem B yuvasından çalışıyor, dolayısıyla B yuvası önyüklenebilir, başarılı ve etkin yuvadır. A yuvasının içeriği güncellenmekte ancak henüz tamamlanmadığından, A Yuvası başlatılamaz olarak işaretlendi. Bu durumda yeniden başlatma, B yuvasından önyüklemeye devam etmelidir.
  • Güncelleme uygulandı, yeniden başlatma bekleniyor : Sistem B yuvasından çalışıyor, B yuvası önyüklenebilir ve başarılı, ancak A yuvası etkin olarak işaretlendi (ve bu nedenle önyüklenebilir olarak işaretlendi). Yuva A henüz başarılı olarak işaretlenmedi ve önyükleyici tarafından yuva A'dan bazı önyükleme denemeleri yapılmalıdır.
  • Sistem yeni güncellemeyle yeniden başlatıldı : Sistem A yuvasından ilk kez çalışıyor, yuva B hala önyüklenebilir ve başarılı, yuva A yalnızca önyüklenebilir ve hala etkin ancak başarılı değil. Bir kullanıcı alanı arka plan programı, update_verifier , bazı kontroller yapıldıktan sonra A yuvasını başarılı olarak işaretlemelidir.

Akış güncelleme desteği

Kullanıcı cihazlarının /data üzerinde güncelleme paketini indirmek için her zaman yeterli alanı yoktur. Ne OEM'ler ne de kullanıcılar bir /cache bölümünde yer kaybetmek istemediğinden, bazı kullanıcılar cihazın güncelleme paketini saklayacak hiçbir yeri olmadığı için güncelleme yapmazlar. Bu sorunu gidermek için Android 8.0, blokları /data üzerinde depolamak zorunda kalmadan blokları indirilirken doğrudan B bölümüne yazan akış A/B güncellemeleri için destek ekledi. A/B güncellemelerinin akışı neredeyse hiç geçici depolamaya ihtiyaç duymaz ve yaklaşık 100 KiB meta veri için yeterli depolama gerektirir.

Android 7.1'de akış güncellemelerini etkinleştirmek için aşağıdaki yamaları seçin:

Bu yamalar, Google Mobil Hizmetleri (GMS) veya başka bir güncelleme istemcisi kullanılarak Android 7.1 ve sonraki sürümlerde A/B güncellemelerinin akışını desteklemek için gereklidir.

A/B güncellemesinin ömrü

Güncelleme işlemi, bir OTA paketi (kodda yük olarak anılır) indirilmeye hazır olduğunda başlar. Cihazdaki politikalar, pil düzeyine, kullanıcı etkinliğine, şarj durumuna veya diğer politikalara bağlı olarak yük indirme ve uygulamayı erteleyebilir. Ayrıca, güncelleme arka planda çalıştığı için kullanıcılar bir güncellemenin devam ettiğini bilmeyebilir. Tüm bunlar, ilkeler, beklenmeyen yeniden başlatmalar veya kullanıcı eylemleri nedeniyle güncelleme işleminin herhangi bir noktada kesintiye uğrayabileceği anlamına gelir.

İsteğe bağlı olarak, OTA paketindeki meta veriler, güncellemenin yayınlanabileceğini gösterir; aynı paket, akışsız kurulum için de kullanılabilir. Sunucu, istemciye akış olduğunu söylemek için meta verileri kullanabilir, böylece istemci, update_engine doğru şekilde OTA'yı devreder. Kendi sunucuları ve istemcileri olan cihaz üreticileri, sunucunun güncellemenin yayınlandığını belirlemesini (veya tüm güncellemelerin yayınlandığını varsaymasını) ve istemcinin akış için update_engine doğru çağrıyı yapmasını sağlayarak akış güncellemelerini etkinleştirebilir. Üreticiler, istemciye bir bayrak göndermek için paketin akış varyantı olduğu gerçeğini kullanarak çerçeve tarafına akış olarak el atılmasını tetikleyebilir.

Bir yük kullanılabilir olduktan sonra güncelleme işlemi aşağıdaki gibidir:

Adım Aktiviteler
1 Geçerli yuva (veya "kaynak yuva") markBootSuccessful() .
2 Kullanılmayan yuva (veya "hedef yuva"), setSlotAsUnbootable() işlevi çağrılarak başlatılamaz olarak işaretlenir. Mevcut yuva, önyükleyicinin yakında geçersiz verilere sahip olacak kullanılmayan yuvaya geri dönmesini önlemek için güncellemenin başlangıcında her zaman başarılı olarak işaretlenir. Sistem bir güncellemeyi uygulamaya başlayabileceği noktaya ulaştıysa, diğer ana bileşenler bozulsa bile (bir kilitlenme döngüsündeki kullanıcı arayüzü gibi) mevcut yuva başarılı olarak işaretlenir, çünkü bunları düzeltmek için yeni yazılımı zorlamak mümkündür. sorunlar.

Güncelleme yükü, yeni sürüme güncelleme talimatları içeren opak bir blobdur. Güncelleme yükü aşağıdakilerden oluşur:
  • Meta veriler . Güncelleme yükünün nispeten küçük bir kısmı olan meta veriler, hedef yuvadaki yeni sürümü üretmek ve doğrulamak için bir operasyon listesi içerir. Örneğin, bir işlem belirli bir bloğu açabilir ve onu hedef bölümdeki belirli bloklara yazabilir veya bir kaynak bölümden okuyabilir, ikili yama uygulayabilir ve hedef bölümdeki belirli bloklara yazabilir.
  • Ekstra veri . Güncelleme yükünün büyük kısmı olarak, işlemlerle ilişkili ekstra veriler, bu örneklerde sıkıştırılmış blob veya ikili yamadan oluşur.
3 Yük meta verileri indirilir.
4 Metadata'da tanımlanan her işlem için sırasıyla ilişkili veriler (varsa) belleğe indirilir, işlem uygulanır ve ilişkili bellek atılır.
5 Tüm bölümler yeniden okunur ve beklenen karmaya göre doğrulanır.
6 Yükleme sonrası adım (varsa) çalıştırılır. Herhangi bir adımın yürütülmesi sırasında bir hata olması durumunda, güncelleme başarısız olur ve muhtemelen farklı bir yük ile yeniden denenir. Şimdiye kadarki tüm adımlar başarılı olduysa, güncelleme başarılı olur ve son adım yürütülür.
7 Kullanılmayan yuva , setActiveBootSlot() çağrılarak etkin olarak işaretlenir. Kullanılmayan yuvayı etkin olarak işaretlemek, önyüklemenin biteceği anlamına gelmez. Önyükleyici (veya sistemin kendisi), başarılı bir durumu okumazsa, etkin yuvayı geri değiştirebilir.
8 Yükleme sonrası (aşağıda açıklanmıştır), eski sürümde çalışmaya devam ederken "yeni güncelleme" sürümünden bir program çalıştırmayı içerir. OTA paketinde tanımlanmışsa, bu adım zorunludur ve program çıkış kodu 0 ile dönmelidir; aksi takdirde güncelleme başarısız olur.
9 Sistem başarılı bir şekilde yeni yuvada yeterince uzağa önyükleme yaptıktan ve yeniden başlatma sonrası kontrolleri tamamladıktan sonra, şu anda geçerli yuva (eskiden "hedef yuva") markBootSuccessful() çağrılarak başarılı olarak işaretlenir.

Yükleme sonrası

Kurulum sonrası adımın tanımlandığı her bölüm için update_engine , yeni bölümü belirli bir konuma bağlar ve OTA'da belirtilen programı, takılı bölüme göre yürütür. Örneğin, kurulum sonrası program sistem bölümünde usr/bin/postinstall olarak tanımlanmışsa, kullanılmayan yuvadaki bu bölüm sabit bir konuma ( /postinstall_mount gibi) ve /postinstall_mount/usr/bin/postinstall komutu çalıştırılır.

Yükleme sonrası başarılı olmak için eski çekirdeğin şunları yapabilmesi gerekir:

  • Yeni dosya sistemi biçimini bağlayın . Dosya sistemi türü, sıkıştırılmış bir dosya sistemi (örn. SquashFS) kullanılıyorsa kullanılan sıkıştırma algoritması gibi ayrıntılar da dahil olmak üzere eski çekirdekte destek olmadığı sürece değişemez.
  • Yeni bölümün yükleme sonrası program biçimini anlayın . Yürütülebilir ve Bağlanabilir Biçim (ELF) ikili dosyası kullanılıyorsa, eski çekirdekle uyumlu olmalıdır (örneğin, mimari 32'den 64-bit'e geçerse, eski bir 32-bit çekirdek üzerinde çalışan 64-bit yeni bir program). Yükleyiciye ( ld ) başka yollar kullanması veya statik bir ikili oluşturma talimatı verilmediği sürece, kitaplıklar yeni sistemden değil eski sistem görüntüsünden yüklenecektir.

Örneğin, eski sistemin kabuk ikili dosyası tarafından #! işaretçisi), ardından daha karmaşık bir ikili yükleme sonrası programı yürütmek için yeni ortamdan kitaplık yolları ayarlayın. Alternatif olarak, ana sistem bölümündeki dosya sistemi biçiminin geriye dönük uyumluluk sorunları veya atlama taşı güncellemeleri olmadan güncellenmesini sağlamak için, daha küçük bir ayrılmış bölümden yükleme sonrası adımı çalıştırabilirsiniz; bu, kullanıcıların bir fabrika görüntüsünden doğrudan en son sürüme güncelleme yapmasına olanak tanır.

Yeni kurulum sonrası program, eski sistemde tanımlanan SELinux ilkeleriyle sınırlıdır. Bu nedenle, kurulum sonrası adım, belirli bir cihazda tasarımın gerektirdiği görevleri veya diğer en iyi çaba gerektiren görevleri gerçekleştirmek için uygundur (örneğin, A/B özellikli bellenimi veya önyükleyiciyi güncelleme, yeni sürüm için veritabanlarının kopyalarını hazırlama, vb.). ). Yükleme sonrası adım, yeniden başlatmadan önce öngörülemeyen izinler gerektiren tek seferlik hata düzeltmeleri için uygun değildir .

Seçilen kurulum sonrası program, kurulum postinstall SELinux bağlamında çalışır. Yeni bağlanan bölümdeki tüm dosyalar, bu yeni sisteme yeniden başladıktan sonra niteliklerinin ne olduğuna bakılmaksızın postinstall_file ile etiketlenecektir. Yeni sistemdeki SELinux özniteliklerinde yapılan değişiklikler, kurulum sonrası adımı etkilemeyecektir. Yükleme sonrası programın ek izinlere ihtiyacı varsa, bunlar yükleme sonrası içeriğe eklenmelidir.

Yeniden başlattıktan sonra

Yeniden başlattıktan sonra update_verifier , dm-verity kullanarak bütünlük kontrolünü tetikler. Bu kontrol, Java servislerinin güvenli bir geri dönüşü önleyecek geri dönüşü olmayan değişiklikler yapmasını önlemek için zigottan önce başlar. Bu işlem sırasında, doğrulanmış önyükleme veya dm-verity herhangi bir bozulma tespit ederse, önyükleyici ve çekirdek de yeniden başlatmayı tetikleyebilir. Kontrol tamamlandıktan sonra update_verifier , önyüklemeyi başarılı olarak işaretler.

update_verifier yalnızca AOSP kodunu kullanırken bir A/B OTA paketine dahil olan /data/ota_package/care_map.txt içinde listelenen blokları okuyacaktır. GmsCore gibi Java sistem güncelleme istemcisi care_map.txt dosyasını ayıklar, cihazı yeniden başlatmadan önce erişim iznini ayarlar ve sistem yeni sürüme başarıyla önyükleme yaptıktan sonra ayıklanan dosyayı siler.