בדף הזה מתוארים השינויים שנוספו ל-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 אחרים).
פרטים נוספים זמינים במאמרים הבאים:
- https://android.googlesource.com/platform/build/+/4d66adfd0e6d599d8502007e4ea9aaf82e95569f
- https://android.googlesource.com/platform/build/+/379f9f9cec4fe1c66b6d60a6c19fecb81b9eb410
- https://android.googlesource.com/platform/build/+/7c3e3f8314eec2c053012dd97d2ae649ebeb5653
- https://android.googlesource.com/platform/build/+/5c64b4e81c1331cab56d8a8c201f26bb263b630c
ספריית 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 שונות, לכן לא כדאי להשתמש בהן. כאן יש כמה אפשרויות לביטול פקודות המאקרו האלה:
- צריך להסיר אותן. לדוגמה, אפשר להיעזר ב https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f.
- כדי לזהות באופן ייחודי את הקובץ הבינארי שרץ, צריך לקרוא את מזהה ה-build מהכותרת של ELF.
-
כדי לדעת מתי פיתחנו את מערכת ההפעלה, אפשר לקרוא את ה
ro.build.date
(הקוד הזה רלוונטי הכול מלבד גרסאות build מצטברות, שאולי לא מתעדכנות בתאריך הזה). לדוגמה, אפשר להיעזר בקישור אל https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84.
חותמות זמן מוטמעות בארכיונים (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.
לדוגמה:
- https://android.googlesource.com/platform/packages/apps/camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
הפעלת חישוב האימות במכשיר
אם משתמשים ב-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 הבאים:
- יוצר קובצי הודעה. היוצר של קובץ NOTICE השתנה כדי ליצור אוספים של הודעות טקסט לשחזור. למידע נוסף, אפשר לעיין ב-CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64.
- Java Android Compiler Kit (Jack). ל-Jack Toolchain נדרש עדכון של תטפל מדי פעם בשינויים בסדר הבנייה שנוצר. רכיבי גישה דטרמיניסטיים עבור נוספו ל-toolchain: https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b.
- מהדר AOT (dex2oat). הקובץ הבינארי של מהדר (compiler) ART קיבל עדכון ש הוסיף אפשרות ליצירת תמונה דטרמיניסטית: https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9.
-
קובץ libpac.so (V8). כל גרסת build יוצרת
/system/lib/libpac.so
כי תמונת המצב של V8 משתנה בכל גרסת build. הפתרון היה להסיר את תמונת המצב: https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29. - קובצי אפליקציה לפני dexopt (.odex). הקבצים לפני dexopt (.odex) מכילה מרווח פנימי לא מאותחל במערכות של 64 ביט. השגיאה תוקנה: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029.
שימוש בכלי להבדלים ב-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, יכול להיות שהם כבר יודעים את האפליקציה המעודכנת, או גרסה חדשה יותר, שהתקבלה ישירות מחנויות האפליקציות.