Penyimpanan dalam cache APK

Dokumen ini menjelaskan desain solusi caching APK untuk penginstalan cepat aplikasi yang dimuat sebelumnya di perangkat yang mendukung partisi A/B.

OEM dapat menempatkan pramuat dan aplikasi populer di cache APK yang disimpan di partisi B yang sebagian besar kosong di perangkat baru yang dipartisi A/B tanpa memengaruhi ruang data yang terlihat oleh pengguna. Dengan adanya cache APK di perangkat, perangkat baru atau yang baru direset ke setelan pabrik siap digunakan hampir seketika, tanpa perlu mendownload file APK dari Google Play.

Kasus penggunaan

  • Menyimpan aplikasi yang dimuat sebelumnya di partisi B untuk penyiapan yang lebih cepat
  • Menyimpan aplikasi populer di partisi B untuk pemulihan yang lebih cepat

Prasyarat

Untuk menggunakan fitur ini, perangkat memerlukan:

  • Rilis Android 8.1 (O MR1) diinstal
  • Partisi A/B diterapkan

Konten yang sudah dimuat sebelumnya hanya dapat disalin selama booting pertama. Hal ini karena pada perangkat yang mendukung update sistem A/B, partisi B sebenarnya tidak menyimpan file image sistem, tetapi konten yang dimuat sebelumnya seperti resource demo retail, file OAT, dan cache APK. Setelah resource disalin ke partisi /data (hal ini terjadi saat booting pertama), partisi B akan digunakan oleh update over-the-air (OTA) untuk mendownload versi terbaru image sistem.

Oleh karena itu, cache APK tidak dapat diupdate melalui OTA; cache APK hanya dapat dimuat sebelumnya di pabrik. Reset ke setelan pabrik hanya memengaruhi partisi /data. Partisi B sistem masih memiliki konten yang dimuat sebelumnya hingga image OTA didownload. Setelah reset ke setelan pabrik, sistem akan melakukan booting pertama lagi. Artinya, caching APK tidak tersedia jika image OTA didownload ke partisi B, lalu perangkat direset ke setelan pabrik.

Penerapan

Pendekatan 1. Konten di partisi system_other

Pro: Konten yang sudah dimuat tidak akan hilang setelah reset ke setelan pabrik—konten tersebut akan disalin dari partisi B setelah perangkat di-reboot.

Con: Memerlukan ruang di partisi B. Booting setelah reset ke setelan pabrik memerlukan waktu tambahan untuk menyalin konten yang dimuat sebelumnya.

Agar pramuat dapat disalin selama booting pertama, sistem akan memanggil skrip di /system/bin/preloads_copy.sh. Skrip dipanggil dengan satu argumen (jalur ke direktori pemasangan hanya baca untuk partisi system_b):

Untuk mengimplementasikan fitur ini, lakukan perubahan khusus perangkat ini. Berikut adalah contoh dari Marlin:

  1. Tambahkan skrip yang melakukan penyalinan ke device-common.mk file (dalam hal ini, device/google/marlin/device-common.mk), seperti berikut:
    # Script that copies preloads directory from system_other to data partition
    PRODUCT_COPY_FILES += \
        device/google/marlin/preloads_copy.sh:system/bin/preloads_copy.sh
    
    Temukan sumber skrip contoh di: device/google/marlin/preloads_copy.sh
  2. Edit file init.common.rc agar membuat direktori dan subdirektori yang diperlukan /data/preloads yang diperlukan:
    mkdir /data/preloads 0775 system system
    mkdir /data/preloads/media 0775 system system
    mkdir /data/preloads/demo 0775 system system
    
    Temukan sumber file init contoh di: device/google/marlin/init.common.rc
  3. Tentukan domain SELinux baru dalam file preloads_copy.te:
    type preloads_copy, domain, coredomain;
    type preloads_copy_exec, exec_type, vendor_file_type, file_type;
    
    init_daemon_domain(preloads_copy)
    
    allow preloads_copy shell_exec:file rx_file_perms;
    allow preloads_copy toolbox_exec:file rx_file_perms;
    allow preloads_copy preloads_data_file:dir create_dir_perms;
    allow preloads_copy preloads_data_file:file create_file_perms;
    allow preloads_copy preloads_media_file:dir create_dir_perms;
    allow preloads_copy preloads_media_file:file create_file_perms;
    
    # Allow to copy from /postinstall
    allow preloads_copy system_file:dir r_dir_perms;
    
    Temukan file domain SELinux contoh di: /device/google/marlin/+/android17-release/sepolicy/preloads_copy.te
  4. Daftarkan domain dalam file /sepolicy/file_contexts baru:
    /system/bin/preloads_copy\.sh     u:object_r:preloads_copy_exec:s0
    
    Temukan file konteks SELinux contoh di: device/google/marlin/sepolicy/preloads_copy.te
  5. Pada waktu build, direktori dengan konten yang dimuat sebelumnya harus disalin ke partisi system_other:
    # Copy contents of preloads directory to system_other partition
    PRODUCT_COPY_FILES += \
        $(call find-copy-subdir-files,*,vendor/google_devices/marlin/preloads,system_other/preloads)
    
    Berikut adalah contoh perubahan dalam Makefile yang memungkinkan penyalinan resource cache APK dari repositori Git vendor (dalam kasus kami, vendor/google_devices/marlin/preloads) ke lokasi di partisi system_other yang nantinya akan disalin ke /data/preloads saat perangkat melakukan booting untuk pertama kalinya. Skrip ini berjalan pada waktu build untuk menyiapkan image system_other. Skrip ini mengharapkan konten yang dimuat sebelumnya tersedia di vendor/google_devices/marlin/preloads. OEM bebas memilih nama/jalur repositori yang sebenarnya.
  6. Cache APK terletak di /data/preloads/file_cache dan memiliki tata letak berikut:
    /data/preloads/file_cache/
        app.package.name.1/
              file1
              fileN
        app.package.name.N/
    
    Ini adalah struktur direktori akhir di perangkat. OEM bebas memilih pendekatan implementasi apa pun selama struktur file akhir mereplikasi struktur file yang dijelaskan di atas.

Pendekatan 2. Konten pada image data pengguna di-flash di pabrik

Pendekatan alternatif ini mengasumsikan bahwa konten yang dimuat sebelumnya sudah disertakan dalam direktori /data/preloads di partisi /data.

Pro: Langsung berfungsi—tidak perlu melakukan penyesuaian perangkat untuk menyalin file saat booting pertama. Konten sudah ada di partisi /data.

Con: Konten yang dimuat sebelumnya akan hilang setelah reset ke setelan pabrik. Meskipun hal ini mungkin dapat diterima untuk beberapa orang, hal ini mungkin tidak selalu berfungsi untuk OEM yang mereset perangkat ke setelan pabrik setelah melakukan pemeriksaan kontrol kualitas.

Metode @SystemApi baru, getPreloadsFileCache(), ditambahkan ke android.content.Context. Metode ini menampilkan jalur absolut ke direktori khusus aplikasi dalam cache yang dimuat sebelumnya.

Metode baru, IPackageManager.deletePreloadsFileCache, ditambahkan yang memungkinkan penghapusan direktori pramuat untuk mengklaim kembali semua ruang. Metode ini hanya dapat dipanggil oleh aplikasi dengan SYSTEM_UID, yaitu server sistem atau Setelan.

Persiapan aplikasi

Hanya aplikasi dengan hak istimewa yang dapat mengakses direktori cache pramuat. Untuk akses tersebut, aplikasi harus diinstal di direktori /system/priv-app.

Validasi

  • Setelah booting pertama, perangkat harus memiliki konten di direktori /data/preloads/file_cache.
  • Konten di direktori file_cache/ harus dihapus jika perangkat kehabisan penyimpanan.

Gunakan aplikasi ApkCacheTest contoh untuk menguji cache APK.

  1. Buat aplikasi dengan menjalankan perintah ini dari direktori utama:
    make ApkCacheTest
    
  2. Instal aplikasi sebagai aplikasi dengan hak istimewa. (Ingat, hanya aplikasi dengan hak istimewa yang dapat mengakses cache APK.) Hal ini memerlukan perangkat yang telah di-root:
    adb root && adb remount
    adb shell mkdir /system/priv-app/ApkCacheTest
    adb push $ANDROID_PRODUCT_OUT/data/app/ApkCacheTest/ApkCacheTest.apk /system/priv-app/ApkCacheTest/
    adb shell stop && adb shell start
    
  3. Simulasikan direktori cache file dan kontennya jika diperlukan (juga memerlukan hak istimewa root):
    adb shell mkdir -p /data/preloads/file_cache/com.android.apkcachetest
    adb shell restorecon -r /data/preloads
    adb shell "echo "Test File" > /data/preloads/file_cache/com.android.apkcachetest/test.txt"
    
  4. Uji aplikasi. Setelah menginstal aplikasi dan membuat direktori file_cache pengujian, buka aplikasi ApkCacheTest. Aplikasi ini akan menampilkan satu file test.txt dan kontennya. Lihat screenshot ini untuk melihat tampilan hasil ini di antarmuka pengguna.

    Gambar 1. Hasil ApkCacheTest.