הקטנת גודל OTA

בדף הזה מתוארים השינויים שנוספו ל-AOSP כדי לצמצם שינויים מיותרים בקבצים בין גרסאות build. מטמיעי מכשירים שמנהלים מערכות build משלהם יכולים להשתמש במידע הזה כקו מנחה על הקטנת הנפח של עדכוני התקשורת (OTA) שלהם.

מדי פעם עדכוני OTA ב-Android מכילים קבצים שהשתנו שלא תואמים לשינויי קוד. הם בעצם build של ארטיפקטים של המערכת. הדבר יכול להתרחש כאשר אותו קוד, שנוצר במיקומים שונים מספר פעמים, מספריות שונות או במכונות שונות, מייצרות . קבצים עודפים כאלו מגדילים את הגודל של תיקון OTA, וקשה לקבוע איזה קוד השתנה.

כדי להפוך את התוכן של OTA לשקיפות יותר, AOSP כולל שינויים במערכת build כדי להקטין את הגודל של תיקונים OTA. שינויי קבצים מיותרים בין גרסאות build נמחקו, ורק קבצים הקשורים לתיקונים נכללים בעדכוני OTA. AOSP כולל גם לכלי build דיפרנציאליות, שמסנן את השגיאות כדי לספק הבדלים נקיים יותר של קובץ build, כלי מיפוי לבלוקים, שעוזר להמשיך להקצות חסימות עקביים.

מערכת build יכולה ליצור תיקונים גדולים שלא לצורך, בכמה דרכים. כדי לצמצם את הסיכון, ב-Android מגרסה 8.0 ואילך, הוטמעו תכונות חדשות כדי להקטין את גודל התיקון הבדלים בקובץ. השיפורים שהפחיתו את גודל החבילות לעדכון OTA כוללים את השיפורים הבאים:

  • שימוש ב-Brotli, אלגוריתם לדחיסה ללא אובדן נתונים, המשמש באופן כללי בתמונות בעדכוני מכשיר שאינם מסוג A/B. אפשר להתאים אישית את Brotli כדי לבצע אופטימיזציה דחיסה. בעדכונים גדולים יותר שמורכבים משני בלוקים או יותר במערכת הקבצים (עבור לדוגמה, system.img), יצרני מכשירים או שותפים יכולים להוסיף מכשירים משלהם אלגוריתמים לדחיסה, ויכולים להשתמש באלגוריתמים שונים של דחיסה על בלוקים שונים של אותו עדכון.
  • שימוש בדחיסה מחדש של Puffin, כלי דטרמיניסטי לתיקון קבצים של שידורים חיים שמטפלים בפונקציות הדחיסה וההבדל כדי ליצור עדכוני A/B OTA.
  • שינויים בשימוש בכלי ליצירת דלתא, כמו האופן שבו bsdiff משמשת לדחיסת תיקונים. ב-Android 9 ואילך, הכלי bsdiff בוחר את אלגוריתם הדחיסה שיספק את תוצאות הדחיסה הטובות ביותר לתיקון.
  • שיפורים update_engine גרמה לצריכת זיכרון נמוכה יותר כאשר הופעלו תיקונים לעדכוני מכשיר A/B.
  • שיפורים בפיצול קובצי ZIP גדולים לעדכוני OTA מבוססי-בלוקים. מצב ב- imgdiff מפצלת קובצי APK גדולים במיוחד, בהתאם לשמות הרשומות. זה מייצר מדבקה קטנה יותר בהשוואה באמצעות פיצול לינארי של קבצים ובאמצעות הכלי bsdiff כדי לדחוס אותם.

בקטעים הבאים נדון בבעיות שונות שמשפיעות על הגדלים של עדכוני OTA, בפתרונות שלהן ודוגמאות להטמעה ב-AOSP.

סדר הקבצים

הבעיה: מערכות הקבצים לא מבטיחה סדר קבצים כשמוצגת בקשה להצגת רשימה של בספרייה, אם כי בדרך כלל זה אותו תשלום. כלים כמו ls ממיינת את התוצאות כברירת מחדל, אבל הפונקציה עם התו הכללי לחיפוש משמשת פקודות כמו כי find ו-make לא ממיינים. לפני השימוש בכלים האלה, עליך למיין את הפלט.

הפתרון: כאשר משתמשים בכלים כמו find ו- make עם הפונקציה עם התו הכללי לחיפוש. צריך למיין את הפלט של הפקודות האלה לפני השימוש אותם. כשמשתמשים ב-$(wildcard) או ב-$(shell find) ב- Android.mk קבצים, כדאי למיין גם אותם. כלים מסוימים, כמו Java, כן ממיינים את הקלט, לפני שממיינים את הקבצים, מוודאים שהכלי שבו אתם משתמשים עדיין לא עשה זאת.

דוגמאות: מקרים רבים תוקנו במערכת ה-build הבסיסית באמצעות מאקרו all-*-files-under מובנה, שכולל all-cpp-files-under (כי כמה הגדרות מפוזרות בקובצי makefile אחרים). פרטים נוספים זמינים במאמרים הבאים:

ספריית Build

הבעיה: שינוי הספרייה שבה הדברים נבנים עלול לגרום הבינאריים יהיו שונים. רוב הנתיבים בגרסת ה-build של Android הם נתיבים יחסיים, __FILE__ ב-C/C++ אין בעיה. עם זאת, סמלי ניפוי הבאגים מקודדים את כברירת מחדל, וה-.note.gnu.build-id נוצר מגיבוב (hash) של הקוד הבינארית מראש, כך שהוא ישתנה אם הסמלים של ניפוי הבאגים ישתנו.

הפתרון: ב-AOSP נעשה עכשיו שימוש בנתיבי ניפוי באגים באופן יחסי. לפרטים נוספים אפשר לעיין ב-CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02.

חותמות זמן

הבעיה: חותמות הזמן בפלט ה-build גורמות לשינויים מיותרים בקובץ. סביר להניח שזה יקרה במיקומים הבאים:

  • __DATE__/__TIME__/__TIMESTAMP__ פקודות מאקרו בקוד C או C++.
  • חותמות זמן שמוטמעות בארכיונים מבוססי-ZIP.

פתרונות או דוגמאות: כדי להסיר חותמות זמן מהפלט של ה-build, משתמשים ההוראות הבאות __DATE__/__TIME__/__TIMESTAMP__ ב-C/C++. וגם חותמות זמן מוטמעות בארכיונים.

__DATE__/__TIME__/__TIMESTAMP__ ב-C/C++

פקודות המאקרו האלה תמיד מפיקות פלטים שונים לגרסאות build שונות, לכן לא כדאי להשתמש בהן. כאן יש כמה אפשרויות לביטול פקודות המאקרו האלה:

חותמות זמן מוטמעות בארכיונים (zip, צנצנת)

מערכת Android 7.0 פתרה את הבעיה של חותמות זמן מוטמעות בארכיוני ZIP על ידי הוספה של -X לכל השימושים בפקודה zip. פעולה זו הסירה את UID/GID של ואת חותמת הזמן המורחבת של Unix מקובץ ה-ZIP.

כלי חדש, ziptime (ממוקם ב: /platform/build/+/main/tools/ziptime/) מאפס את חותמות הזמן הרגילות בכותרות ה-ZIP. פרטים נוספים זמינים קובץ README.

הכלי signapk מגדיר חותמות זמן עבור קובצי ה-APK שעשויות להשתנות בהתאם אזור הזמן של השרת. לפרטים נוספים אפשר לעיין ב-CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.

מחרוזות גרסה

הבעיה: לעיתים קרובות מצורפים מחרוזות של גרסת APK את הקוד BUILD_NUMBER לגרסאות שלהם בתוך הקוד. גם אם שום דבר אחר לא השתנה ב-APK, כתוצאה מכך, ה-APK עדיין יהיה שונה.

הפתרון: מסירים את מספר ה-build מהמחרוזת של גרסת ה-APK.

לדוגמה:

הפעלת חישוב האימות במכשיר

אם משתמשים ב-dm-verity מופעלת במכשיר, וכלי OTA אוספים באופן אוטומטי את ההגדרות האישיות של האימות להפעיל חישוב אימות במכשיר. כך ניתן לחשב חסימות אימות ב-Android במקום להיות מאוחסנים כבייטים גולמיים בחבילת ה-OTA. ניתן להשתמש בבלוקים של גרסאות כ-16MB למחיצה של 2GB.

עם זאת, חישוב האימות במכשיר עשוי להימשך זמן רב. באופן ספציפי, קוד תיקון השגיאה עשוי להימשך זמן רב. במכשירי Pixel, בדרך כלל התהליך נמשך עד 10 דקות. במכשירים פשוטים, התהליך עשוי להימשך זמן רב יותר. אם רוצים להשבית את האימות במכשיר אבל עדיין להפעיל dm-verity, תוכלו לעשות זאת על ידי העברת --disable_fec_computation לכלי ota_from_target_files כאשר יצירת עדכון OTA. הסימון הזה משבית את חישוב האיכות במכשיר במהלך עדכוני OTA. היא מקצרת את זמן ההתקנה של OTA, אבל מגדילה את גודל חבילת OTA. אם המכשיר לא dm-verity מופעל, העברת הסימון הזה לא משפיעה.

כלי build עקביים

הבעיה: כלים שיוצרים קבצים מותקנים חייבים להיות עקביים ( הקלט צריך תמיד להפיק את אותו הפלט).

פתרונות או דוגמאות: נדרשו שינויים בכלי ה-build הבאים:

שימוש בכלי להבדלים ב-build

במקרים שבהם לא ניתן לבטל שינויים בקבצים שקשורים ל-build, AOSP כולל כלי להבדלים ב-build, target_files_diff.py לשימוש בהשוואה בין שתי חבילות קבצים. הכלי הזה מבצע הבדל רקורסיבי בין build חוץ משינויים נפוצים בקבצים שקשורים ל-build, כמו

  • השינויים הצפויים בפלט ה-build (לדוגמה, בגלל שינוי במספר ה-build).
  • שינויים בגלל בעיות ידועות במערכת ה-build הנוכחית.

כדי להשתמש בכלי להבדלים ב-build, מריצים את הפקודה הבאה:

target_files_diff.py dir1 dir2

dir1 ו-dir2 הן ספריות בסיס שמכילות את היעד שחולץ בכל גרסת build.

שמירה על עקביות בהקצאת הבלוקים

לגבי קובץ נתון, למרות שהתוכן שלו נשאר זהה בין שני גרסאות build, הבלוקים בפועל שבהם נמצאים הנתונים. כתוצאה מכך, המעדכן צריך לבצע קלט/פלט (I/O) מיותר כדי להזיז את הבלוקים לצורך עדכון OTA.

בעדכון של Virtual A/B OTA, קלט/פלט מיותר עלול להגדיל משמעותית את נפח האחסון הנדרש כדי לשמור את קובץ ה-snapshot של ההעתקה. בעדכון OTA שאינו A/B, הזזת הבלוקים עדכון OTA תורם לזמן העדכון ככל שיש יותר קלט/פלט בעקבות העברות חסימה.

כדי לפתור את הבעיה הזו, ב-Android 7.0 Google הרחיבה את הכלי make_ext4fs עבור שמירה על עקביות בהקצאת הבלוקים בכל גרסאות ה-build. הכלי make_ext4fs מקבל דגל -d base_fs אופציונלי שמנסה להקצות קבצים לאותן בלוקים כשיוצרים תמונת ext4. אפשר לחלץ את קובצי מיפוי הבלוקים (כמו base_fs קובצי המפה) מקובצי היעד של ה-build הקודם קובץ ZIP. בכל פעם המחיצה ext4, יש קובץ .map הספרייה IMAGES (לדוגמה, IMAGES/system.map תואמת מחיצה system). לאחר מכן ניתן לעשות צ'ק-אין ב-base_fs הקבצים האלה שצוינו באמצעות PRODUCT_<partition>_BASE_FS_PATH, כמו בדוגמה הזו:

  PRODUCT_SYSTEM_BASE_FS_PATH := path/to/base_fs_files/base_system.map
  PRODUCT_SYSTEM_EXT_BASE_FS_PATH := path/to/base_fs_files/base_system_ext.map
  PRODUCT_VENDOR_BASE_FS_PATH := path/to/base_fs_files/base_vendor.map
  PRODUCT_PRODUCT_BASE_FS_PATH := path/to/base_fs_files/base_product.map
  PRODUCT_ODM_BASE_FS_PATH := path/to/base_fs_files/base_odm.map

הפעולה הזו לא עוזרת להקטין את הגודל הכולל של חבילת ה-OTA, אבל היא משפרת את עדכון OTA הביצועים באמצעות הפחתת כמות הקלט/פלט (I/O). במקרה של עדכוני A/B וירטואליים, הפעולה הזו מפחיתה באופן משמעותי את נפח האחסון שנדרש כדי להפעיל את ה-OTA.

הימנעות מעדכון אפליקציות

בנוסף לצמצום ההבדלים בין גרסאות build, אפשר להקטין את עדכוני ה-OTA על ידי החרגת עדכונים אם מדובר באפליקציות שמקבלות עדכונים דרך חנויות האפליקציות. חבילות APK בדרך כלל מהוות חלק משמעותי מחיצות שונות במכשיר. כולל הגרסאות האחרונות של אפליקציות שמתעדכנות על ידי אפליקציה לעדכון OTA עשויה להיות השפעה גדולה על חבילות OTA, ויש מעט מאוד משתמשים . עד שהמשתמשים יקבלו חבילת OTA, יכול להיות שהם כבר יודעים את האפליקציה המעודכנת, או גרסה חדשה יותר, שהתקבלה ישירות מחנויות האפליקציות.