שינויים בהתנהגות ב-Android 7.0

בנוסף לתכונות וליכולות חדשות, Android 7.0 כולל מגוון שינויים בהתנהגות המערכת וב-API. במסמך הזה נתאר כמה מהשינויים העיקריים שחשוב להבין ולקחת בחשבון באפליקציות שלכם.

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

סוללה וזיכרון

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

נמנום

התכונה Doze הוצגה ב-Android 6.0 (רמת API 23) ומאריכה את חיי הסוללה על ידי דחיית פעילויות של המעבד והרשת כשהמשתמש משאיר את המכשיר לא מחובר, נייח והמסך כבוי. ב-Android 7.0 נוספו שיפורים ל-Doze, שמופעלים קבוצת משנה של הגבלות על המעבד והרשת כשהמכשיר לא מחובר והמסך כבוי, אבל לא בהכרח נייח. לדוגמה, כשהמכשיר הנייד נמצא בכיס של המשתמש.

איור שמראה איך התכונה Doze מחילה רמה ראשונה של הגבלות על פעילות המערכת כדי לשפר את חיי הסוללה

איור 1. איור שמראה איך התכונה Doze מחילה רמה ראשונה של הגבלות על פעילות המערכת כדי לשפר את חיי הסוללה.

כשמכשיר פועל על סוללה והמסך כבוי במשך זמן מסוים, המכשיר עובר למצב Doze ומחילה את קבוצת המשנה הראשונה של ההגבלות: הוא משבית את הגישה של האפליקציות לרשת, ומעכב משימות וסנכרון. אם המכשיר נייח למשך זמן מסוים אחרי שהוא נכנס למצב Doze, המערכת מחילה את שאר ההגבלות של Doze על PowerManager.WakeLock, על ההתראות של AlarmManager, על ה-GPS ועל סריקות ה-Wi-Fi. לא משנה אם חלות חלק מההגבלות של מצב 'נמנום' או את כולן, המערכת מוציאה את המכשיר ממצב שינה לחלונות תחזוקה קצרים, שבמהלך התקופה הזו לאפליקציות מורשות גישה לרשת ויכולה להפעיל משימות/סנכרונים שנדחו.

איור שמראה איך התכונה Doze מחילה רמה שנייה של הגבלות על פעילות המערכת אחרי שהמכשיר לא זז במשך זמן מסוים

איור 2. איור שמראה איך התכונה Doze מחילה רמה שנייה של הגבלות על פעילות המערכת אחרי שהמכשיר נמצא במצב נייח במשך זמן מסוים.

חשוב לזכור שהפעלת המסך או חיבור המכשיר מבטלים את מצב Doze ומבטלים את הגבלות העיבוד האלה. ההתנהגות הנוספת לא משפיעה על ההמלצות ועל השיטות המומלצות להתאמת האפליקציה לגרסה הקודמת של Doze שהושקה ב-Android 6.0 (רמת API 23), כפי שמתואר באופטימיזציה ל'נמנום' ול-App Standby. עדיין מומלץ לפעול לפי ההמלצות האלה, למשל להשתמש ב-Firebase Cloud Messaging ‏ (FCM) כדי לשלוח ולקבל הודעות, ולהתחיל לתכנן עדכונים בהתאם להתנהגות הנוספת של Doze.

Project Svelte: אופטימיזציות ברקע

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

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

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

כדי לצמצם את הבעיות האלה, ב-Android 7.0 מופעלות אופטימיזציות הבאות:

  • אפליקציות שמטרגטות את Android מגרסה 7.0 (רמת API‏ 24) ואילך לא מקבלות שידורי CONNECTIVITY_ACTION אם הן מצהירות על מקלט השידור שלהן במניפסט. אפליקציות עדיין יקבלו שידורי CONNECTIVITY_ACTION אם הן יירשמו עם BroadcastReceiver ב-Context.registerReceiver() וההקשר הזה עדיין תקף.
  • המערכת לא שולחת יותר שידורים של ACTION_NEW_PICTURE או ACTION_NEW_VIDEO. האופטימיזציה הזו משפיעה על כל האפליקציות, ולא רק על אלה שמטרגטות ל-Android 7.0.

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

למידע נוסף על אופטימיזציה ברקע ב-Android 7.0 (רמת API 24) ועל אופן ההתאמה של האפליקציה, אפשר לעיין במאמר אופטימיזציה ברקע.

שינויים בהרשאות

גרסת Android 7.0 כוללת שינויים בהרשאות שעשויים להשפיע על האפליקציה שלכם.

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

כדי לשפר את האבטחה של קבצים פרטיים, הגישה לספרייה הפרטית של האפליקציות שמטרגטות ל-Android 7.0 ואילך מוגבלת (0700). ההגדרה הזו מונעת דליפה של מטא-נתונים של קבצים פרטיים, כמו הגודל או הקיום שלהם. לשינוי הזה בהרשאה יש מספר תופעות לוואי:

  • הבעלים של קבצים פרטיים לא יכולים יותר להקל על ההרשאות שלהם, וניסיונות לעשות זאת באמצעות MODE_WORLD_READABLE ו/או MODE_WORLD_WRITEABLE יגרמו ליצירת SecurityException.

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

  • העברת URIs של file:// מחוץ לדומיין החבילה עלולה להשאיר לנמען נתיב שלא ניתן לגשת אליו. לכן, ניסיונות להעביר URI של file:// מפעילים FileUriExposedException. הדרך המומלצת לשתף תוכן של קובץ פרטי היא באמצעות FileProvider.
  • לא ניתן יותר לשתף קבצים שמאוחסנים באופן פרטי לפי שם הקובץ.DownloadManager יכול להיות שאפליקציות מדור קודם יגיעו למצב שבו הן לא יוכלו לגשת ל-COLUMN_LOCAL_FILENAME. אפליקציות שמטרגטות ל-Android 7.0 ואילך גורמות להפעלה של SecurityException כשמנסות לגשת אל COLUMN_LOCAL_FILENAME. אפליקציות מדור קודם שהגדירו את מיקום ההורדה למיקום ציבורי באמצעות DownloadManager.Request.setDestinationInExternalFilesDir() או DownloadManager.Request.setDestinationInExternalPublicDir() עדיין יכולות לגשת לשביל ב-COLUMN_LOCAL_FILENAME, אבל לא מומלץ להשתמש בשיטה הזו. הדרך המועדפת לגשת לקובץ שנחשף על ידי DownloadManager היא באמצעות ContentResolver.openFileDescriptor().

שיתוף קבצים בין אפליקציות

באפליקציות שמיועדות ל-Android 7.0, מסגרת Android אוכפת את מדיניות ה-API של StrictMode, שאוסרת לחשוף מזהים URI מסוג file:// מחוץ לאפליקציה. אם כוונה (intent) שמכילה URI של קובץ יוצאת מהאפליקציה, האפליקציה נכשלת עם חריגה מסוג FileUriExposedException.

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

שיפורים בנגישות

Android 7.0 כולל שינויים שנועדו לשפר את נוחות השימוש בפלטפורמה למשתמשים עם ליקויי ראייה או ראייה חלשה. בדרך כלל, השינויים האלה לא ידרשו שינויים בקוד של האפליקציה, אבל כדאי לבדוק את התכונות האלה ולבדוק אותן באפליקציה כדי להעריך את ההשפעה הפוטנציאלית שלהן על חוויית המשתמש.

זום במסך

ב-Android 7.0, המשתמשים יכולים להגדיר את גודל התצוגה כדי להגדיל או לכווץ את כל הרכיבים במסך, וכך לשפר את הנגישות של המכשיר למשתמשים עם ליקויי ראייה. המשתמשים לא יכולים לשנות את מרחק התצוגה של המסך מעבר לרוחב המסך המינימלי של sw320dp, שהוא הרוחב של Nexus 4, טלפון נפוץ בגודל בינוני.

מסך שבו מוצג גודל המסך ללא זום של מכשיר שבו פועלת קובץ אימג' של מערכת Android 7.0
מסך שבו מוצגת ההשפעה של הגדלת התצוגה של מכשיר שמותקנת בו תמונת מערכת של Android 7.0

איור 3. במסך מימין מוצגת ההשפעה של הגדלת התצוגה של מכשיר שבו פועלת תמונת מערכת של Android 7.0.

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

  • אם אפליקציה מטרגטת רמת API 23 ומטה, המערכת משביתה באופן אוטומטי את כל תהליכי הרקע שלה. כלומר, אם משתמש יוצא מאפליקציה כזו כדי לפתוח את מסך ההגדרות ומשנה את ההגדרה גודל תצוגה, המערכת תרוג את האפליקציה באותו אופן שבו היא תסגור את האפליקציה במצב של מעט זיכרון. אם יש באפליקציה תהליכים בחזית, המערכת תודיע לתהליכים האלה על שינוי התצורה, כפי שמתואר בקטע טיפול בשינויים בסביבת זמן הריצה, בדיוק כמו אם כיוון המכשיר השתנה.
  • אם אפליקציה מטרגטת את Android 7.0, כל התהליכים שלה (בחזית וברקע) יקבלו הודעה על שינוי התצורה, כפי שמתואר בקטע טיפול בשינויים בסביבת זמן הריצה.

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

  • בודקים את האפליקציה במכשיר עם רוחב מסך sw320dp ומוודאים שהיא פועלת כראוי.
  • כשהגדרות המכשיר משתנות, כדאי לעדכן את כל המידע שנשמר במטמון שתלוי בדחיסות, כמו מפות ביטים שנשמרו במטמון או משאבים שנטענו מהרשת. בודקים אם התרחשו שינויים בהגדרות כשהאפליקציה ממשיכה לפעול מהמצב שהושהה.

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

  • מומלץ להימנע מהגדרת מידות ביחידות px, כי הן לא משתנות בהתאם לצפיפות המסך. במקום זאת, צריך לציין את המימדים ביחידות של פיקסלים שאינם תלויים בדחיסות (dp).

הגדרות הראייה באשף ההגדרה

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

קישור אפליקציות NDK לספריות פלטפורמה

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

יש שלוש דרכים שבהן האפליקציה שלכם עשויה לנסות לגשת לממשקי API פרטיים של פלטפורמות:

  • האפליקציה שלכם ניגשת ישירות לספריות פרטיות של הפלטפורמה. עליכם לעדכן את האפליקציה כך שתכלול עותק משלה של הספריות האלה, או להשתמש בממשקי ה-API הציבוריים של NDK.
  • האפליקציה שלכם משתמשת בספרייה של צד שלישי שמקבלת גישה לספריות פרטיות של פלטפורמות. גם אם אתם בטוחים שהאפליקציה שלכם לא ניגשת ישירות לספריות פרטיות, עדיין כדאי לבדוק את האפליקציה בתרחיש הזה.
  • האפליקציה מפנה לספרייה שלא נכללת ב-APK שלה. לדוגמה, מצב כזה יכול לקרות אם ניסית להשתמש בעותק משלך של OpenSSL אבל שכחת לצרף אותו ל-APK של האפליקציה. יכול להיות שהאפליקציה תפעל באופן תקין בגרסאות של פלטפורמת Android שכוללות את libcrypto.so. עם זאת, האפליקציה עלולה לקרוס בגרסאות מאוחרות יותר של Android שלא כוללות את הספרייה הזו (למשל, Android 6.0 ואילך). כדי לפתור את הבעיה, צריך לוודא שכל הספריות שאינן NDK נכללות בחבילת ה-APK.

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

כדי לצמצם את ההשפעה של ההגבלה הזו על אפליקציות שכבר פורסמו, גישה לקבוצה של ספריות שבהן יש שימוש משמעותי – כמו libandroid_runtime.so,‏ libcutils.so,‏ libcrypto.so ו-libssl.so – תהיה זמינה באופן זמני ב-Android 7.0 (רמת API 24) לאפליקציות שמטרגטות רמת API 23 ומטה. אם האפליקציה טוענת את אחת מהספריות האלה, ה-Logcat יוצר אזהרה והודעה קופצת מופיעה במכשיר היעד כדי ליידע אותך. אם מופיעות האזהרות האלה, צריך לעדכן את האפליקציה כך שתכלול עותק משלה של הספריות האלה, או להשתמש רק בממשקי ה-API הציבוריים של NDK. גרסאות עתידיות של פלטפורמת Android עשויות להגביל את השימוש בספריות פרטיות לגמרי ולגרום לקריסת האפליקציה.

כל האפליקציות יוצרות שגיאה בסביבת זמן הריצה כשהן קוראות ל-API שהוא לא ציבורי ולא נגיש באופן זמני. התוצאה היא ש-System.loadLibrary ו-dlopen(3) יחזירו NULL, ועלולים לגרום לקריסה של האפליקציה. עליכם לבדוק את קוד האפליקציה כדי להסיר את השימוש בממשקי API פרטיים של פלטפורמות ולבדוק היטב את האפליקציות באמצעות מכשיר או אמולטור עם Android 7.0 (רמת API 24). אם אתם לא בטוחים שהאפליקציה שלכם משתמשת בספריות פרטיות, תוכלו לבדוק את logcat כדי לזהות את שגיאת זמן הריצה.

בטבלה הבאה מתוארת ההתנהגות שצפוי להתרחש באפליקציה, בהתאם לשימוש בספריות נייטיב פרטיות וברמת ה-API לטירגוט של האפליקציה (android:targetSdkVersion).

ספריות רמת ה-API לטירגוט גישה בסביבת זמן ריצה באמצעות קישור דינמי התנהגות ב-Android 7.0 (רמת API 24) התנהגות עתידית של פלטפורמת Android
NDK ציבורי כל צבע נגיש פועלת כמצופה פועלת כמצופה
פרטית (ספריות פרטיות נגישות באופן זמני) 23 או פחות גישה זמנית הפעולה פועלת כצפוי, אבל מופיעה אזהרה ב-logcat. שגיאת זמן ריצה
פרטי (ספריות פרטיות שזמינות באופן זמני) 24 ומעלה מוגבל שגיאת זמן ריצה שגיאת זמן ריצה
פרטי (אחר) כל צבע מוגבל שגיאת זמן ריצה שגיאת זמן ריצה

בדיקה אם האפליקציה משתמשת בספריות פרטיות

כדי לעזור לכם לזהות בעיות בטעינה של ספריות פרטיות, יכול להיות ש-logcat יפיק אזהרה או שגיאה זמן ריצה. לדוגמה, אם האפליקציה שלך מטרגטת לרמת API 23 ומטה ומנסה לגשת לספרייה פרטית במכשיר עם Android 7.0, יכול להיות שתוצג אזהרה שדומה לזו:

03-21 17:07:51.502 31234 31234 W linker  : library "libandroid_runtime.so"
("/system/lib/libandroid_runtime.so") needed or dlopened by
"/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible
for the namespace "classloader-namespace" - the access is temporarily granted
as a workaround for http://b/26394120

האזהרות האלה בקשר ל-Logcat מציינות איזו ספרייה מנסה לגשת ל-API של פלטפורמה פרטית, אבל לא יגרמו לאפליקציה לקרוס. עם זאת, אם האפליקציה מטרגטת לרמת API 24 ואילך, logcat יוצר את שגיאת זמן הריצה הבאה והאפליקציה עשויה לקרוס:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so"
("/system/lib/libcutils.so") needed or dlopened by
"/system/lib/libnativeloader.so" is not accessible for the namespace
"classloader-namespace"
  at java.lang.Runtime.loadLibrary0(Runtime.java:977)
  at java.lang.System.loadLibrary(System.java:1602)

יכול להיות שתראו את הפלט הזה ב-logcat גם אם האפליקציה שלכם משתמשת בספריות של צד שלישי שמקשרות באופן דינמי לממשקי API פרטיים של פלטפורמות. הכלי readelf ב-Android 7.0DK מאפשר ליצור רשימה של כל הספריות המשותפות המקושרות באופן דינמי בקובץ .so נתון. כדי לעשות זאת, מריצים את הפקודה הבאה:

aarch64-linux-android-readelf -dW libMyLibrary.so

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

ריכזנו כאן כמה פעולות שאפשר לבצע כדי לתקן את סוגי השגיאות האלה ולוודא שהאפליקציה לא תקרוס בעדכוני פלטפורמה עתידיים:

  • אם האפליקציה שלכם משתמשת בספריות פרטיות של פלטפורמה, עליכם לעדכן אותה כך שתכלול עותק משלה של הספריות האלה, או להשתמש בממשקי ה-API הציבוריים של NDK.
  • אם האפליקציה משתמשת בספרייה של צד שלישי שיש לה גישה לסמלים פרטיים, צריך לפנות למחבר הספרייה כדי לעדכן את הספרייה.
  • חשוב לארוז את כל הספריות שאינן NDK ב-APK.
  • משתמשים בפונקציות JNI רגילות במקום ב-getJavaVM וב-getJNIEnv מ-libandroid_runtime.so:
    AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
    AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
    JavaVM::AttachCurrentThread from <jni.h>.
    
  • אפשר להשתמש ב-__system_property_get במקום בסמל property_get הפרטי מ-libcutils.so. כדי לעשות זאת, משתמשים בפקודה __system_property_get עם ההכללה הבאה:
    #include <sys/system_properties.h>

    הערה: הזמינות והתוכן של מאפייני המערכת לא נבדקים באמצעות CTS. פתרון טוב יותר הוא להימנע משימוש בנכסים האלה לגמרי.

  • משתמשים בגרסה המקומית של הסמל SSL_ctrl מ-libcrypto.so. לדוגמה, צריך לקשר באופן סטטי את libcyrpto.a בקובץ .so, או לכלול גרסה מקושרת באופן דינמי של libcrypto.so מ-BoringSSL/‏OpenSSL ולארז אותה ב-APK.

Android for Work

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

  • כדי ש-DPC יוכל להגדיר את האישור, צריך להתקין מתקין של אישור שהוקצה. גם באפליקציות לפרופיל וגם באפליקציות של בעלי המכשיר שמטרגטות את Android 7.0 (API ברמה 24), צריך להתקין את מנהל האישורים שהוקצה לפני שהבקר לניהול מדיניות המכשירים (DPC) קורא ל-DevicePolicyManager.setCertInstallerPackage(). אם מנהל ההתקנה לא מותקן, המערכת תציג את השגיאה IllegalArgumentException.
  • איפוס ההגבלות על סיסמאות עבור אדמינים של מכשירים חלות עכשיו על בעלי הפרופיל. מנהלי מכשירים כבר לא יכולים להשתמש ב-DevicePolicyManager.resetPassword() כדי למחוק סיסמאות או לשנות סיסמאות שכבר מוגדרות. אדמינים של מכשירים עדיין יכולים להגדיר סיסמה, אבל רק אם אין במכשיר סיסמה, קוד אימות או קו ביטול נעילה.
  • הבעלים של המכשיר ושל הפרופיל יכולים לנהל את החשבונות גם אם מוגדרות הגבלות. בעלי המכשיר ובעלי הפרופילים יכולים להפעיל את ממשקי ה-API לניהול חשבונות גם אם יש הגבלות על המשתמשים ב-DISALLOW_MODIFY_ACCOUNTS.
  • בעלי מכשירים יכולים לנהל משתמשים משניים בקלות רבה יותר. כשמכשיר פועל במצב 'בעלי המכשיר', ההגבלה DISALLOW_ADD_USER מוגדרת באופן אוטומטי. כך המשתמשים לא יוכלו ליצור משתמשים משניים לא מנוהלים. בנוסף, השיטות CreateUser() ו-createAndInitializeUser() הוצאו משימוש, והן מוחלפות בשיטה החדשה DevicePolicyManager.createAndManageUser().
  • בעלי המכשירים יכולים לגשת למזהי המכשיר. בעלי המכשיר יכולים לגשת אל כתובת ה-MAC של ה-Wi-Fi של המכשיר באמצעות DevicePolicyManager.getWifiMacAddress(). אם רשת Wi-Fi אף פעם לא הופעלה במכשיר, השיטה הזו מחזירה את הערך null.
  • הגדרת מצב העבודה קובעת את הגישה לאפליקציות לעבודה. כשמצב עבודה מושבת, מרכז האפליקציות של המערכת מציין שאפליקציות לעבודה לא זמינות ומוצגות באפור. הפעלה מחדש של מצב העבודה תחזיר את ההתנהגות הרגילה.
  • כשמתקינים קובץ PKCS #12 שמכיל שרשרת אישורי לקוח ואת המפתח הפרטי המתאים מממשק המשתמש של ההגדרות, אישור ה-CA בשרשרת לא מותקן יותר באחסון המהימן של פרטי הכניסה. הדבר לא משפיע על התוצאה של KeyChain.getCertificateChain() כשאפליקציות מנסים לאחזר את שרשרת האישורים של הלקוח מאוחר יותר. במקרה הצורך, צריך להתקין את אישור ה-CA באחסון של פרטי הכניסה המהימנים דרך ממשק המשתמש של ההגדרות בנפרד, עם פורמט בקידוד DER עם סיומת קובץ .crt או .cer
  • החל מגרסה 7.0 של Android, הרישום והאחסון של טביעות האצבע מנוהלים לכל משתמש בנפרד. אם לקוח מדיניות המכשיר (DPC) של בעלי הפרופיל מטרגט לרמת API‏ 23 (או פחות) במכשיר עם Android 7.0 (רמת API‏ 24), המשתמש עדיין יכול להגדיר טביעת אצבע במכשיר, אבל לאפליקציות העבודה אין גישה לטביעת האצבע של המכשיר. כשה-DPC מטרגט API ברמה 24 ואילך, המשתמש יכול להגדיר את טביעת האצבע במיוחד לפרופיל העבודה. לשם כך, עוברים אל הגדרות > אבטחה > אבטחת פרופיל העבודה.
  • DevicePolicyManager.getStorageEncryptionStatus() מחזיר סטטוס הצפנה חדש ENCRYPTION_STATUS_ACTIVE_PER_USER כדי לציין שההצפנה פעילה ומפתח ההצפנה קשור למשתמש. הסטטוס החדש מוחזר רק אם בקר DPC מטרגט API ברמה 24 ואילך. באפליקציות שמטרגטות רמות API קודמות, הערך ENCRYPTION_STATUS_ACTIVE מוחזר גם אם מפתח ההצפנה ספציפי למשתמש או לפרופיל.
  • ב-Android 7.0, כמה שיטות שבדרך כלל משפיעות על כל המכשיר פועלות באופן שונה אם במכשיר מותקן פרופיל עבודה עם אתגר נפרד לעבודה. במקום להשפיע על המכשיר כולו, השיטות האלה חלות רק על פרופיל העבודה. (הרשימה המלאה של השיטות האלה מופיעה במסמכי התיעוד של DevicePolicyManager.getParentProfileInstance().) לדוגמה, DevicePolicyManager.lockNow() נועל רק את פרופיל העבודה, במקום את המכשיר כולו. בכל אחת מהשיטות האלה, אפשר לקבל את ההתנהגות הישנה על ידי שליחת קריאה ל-method במופע ההורה של DevicePolicyManager. אפשר לקבל את ההורה הזה באמצעות קריאה ל-DevicePolicyManager.getParentProfileInstance(). לדוגמה, אם קוראים לשיטה lockNow() של המכונה ההורה, כל המכשיר נעול.

שמירת הערות

ב-Android 7.0 תוקן באג שגרם לכך שהמערכת התעלמה מההסתרה של ההערות. הבעיה הזו אפשרה לסביבת זמן הריצה לגשת להערות שלא הייתה אמורה לגשת אליהן. ההערות האלה כללו:

  • VISIBILITY_BUILD: מיועד להיות גלוי רק בזמן ה-build.
  • VISIBILITY_SYSTEM: נועדו להיות גלויים בזמן הריצה, אבל רק למערכת הבסיסית.

אם האפליקציה שלך הסתמכה על ההתנהגות הזו, צריך להוסיף מדיניות שמירת נתונים להערות שחייבות להיות זמינות בזמן הריצה. אפשר לעשות את זה באמצעות @Retention(RetentionPolicy.RUNTIME).

שינויים בהגדרות ברירת המחדל של TLS/‏SSL

ב-Android 7.0 מתבצעים השינויים הבאים בהגדרות ברירת המחדל של TLS/SSL (אבטחת שכבת התעבורה)/SSL, שמשמשות אפליקציות ל-HTTPS ולתנועת TLS/SSL אחרת:

  • סטים של אלגוריתמים להצפנה (cipher suite) מסוג RC4 מושבתים עכשיו.
  • סטים של אלגוריתמים להצפנה (cipher suite) מסוג CHACHA20-POLY1305 מופעלים עכשיו.

השבתת RC4 כברירת מחדל עלולה לגרום לשיבושים בחיבור HTTPS או TLS/SSL אם השרת לא מנהל משא ומתן על סט אלגוריתמים מודרני להצפנה. התיקון המועדף הוא לשפר את ההגדרות של השרת כדי לאפשר שימוש בפרוטוקולים ובחבילות הצפנה חזקים ומודרניים יותר. באופן אידיאלי, צריך להפעיל את TLSv1.2 ואת AES-GCM, וגם להפעיל את חבילות ההצפנה של Forward Secrecy (ECDHE) ולהעדיף אותן.

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

הערה: השינויים האלה לא רלוונטיים ל-WebView.

אפליקציות שמטרגטות את Android מגרסה 7.0

השינויים האלה בהתנהגות חלים רק על אפליקציות שמטרגטות ל-Android 7.0 (רמת API 24) ואילך. באפליקציות שעברו הידור (compile) ל-Android 7.0, או שמגדירים את targetSdkVersion ל-Android 7.0 ואילך, חייבים לשנות את האפליקציות שלהן כך שיתמכו בהתנהגויות האלה באופן תקין, במקרים שבהם הן רלוונטיות לאפליקציה.

שינויים בעריכה בסדרה

מערכת Android 7.0 (רמת API 24) תיקנה באג בחישוב של ה-resisVersionUID שמוגדר כברירת מחדל, כאשר הוא לא תואם למפרט.

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

local class incompatible: stream classdesc serialVersionUID = 1234, local class serialVersionUID = 4567

כדי לפתור את הבעיות האלה, צריך להוסיף שדה serialVersionUID לכל כיתה שהושפעה עם הערך stream classdesc serialVersionUID מהודעת השגיאה, למשל 1234 במקרה הזה. השינוי הזה עומד בכל ההמלצות לשיטות מומלצות לכתיבת קוד שרשור, והוא יפעל בכל הגרסאות של Android.

הבאג הספציפי שתוקן היה קשור לנוכחות של שיטות מאתחל סטטיות, כלומר <clinit>. לפי המפרט, נוכחות או היעדר של שיטת initializer סטטית בכיתה ישפיעו על serialVersionUID שמחושב כברירת מחדל עבור הכיתה הזו. לפני תיקון הבאג, החישוב היה בודק גם את הכיתה האב אם לא הייתה לכיתה מאתחלת סטטית.

לשם הבהרה, השינוי הזה לא משפיע על אפליקציות שמטרגטות לרמות API 23 ומטה, מחלקות שיש בהן שדה serialVersionUID או מחלקות עם שיטת מאתחל סטטי.

נקודות חשובות נוספות

  • כשאפליקציה פועלת ב-Android 7.0 אבל מטרגטת רמת API נמוכה יותר, והמשתמש משנה את גודל התצוגה, התהליך של האפליקציה מופסק. האפליקציה צריכה להיות מסוגלת לטפל בתרחיש הזה בצורה חלקה. אחרת, האפליקציה תקרוס כשהמשתמש ישחזר אותה מה'סמלי האפליקציות האחרונות'.

    מומלץ לבדוק את האפליקציה כדי לוודא שההתנהגות הזו לא מתרחשת. אפשר לעשות זאת על ידי גרימת קריסה זהה כשסוגרים את האפליקציה באופן ידני באמצעות DDMS.

    אפליקציות שמטרגטות ל-Android 7.0 (רמת API 24) ואילך לא מושבתות באופן אוטומטי כשמשנים צפיפות. עם זאת, הן עדיין עשויות להגיב בצורה גרועה לשינויים בהגדרות.

  • אפליקציות ב-Android 7.0 אמורות להתמודד בצורה חלקה עם שינויים בהגדרות, ולא לקרוס בהפעלות הבאות. כדי לבדוק את התנהגות האפליקציה, משנים את גודל הגופן (הגדרות > תצוגה > גודל גופן) ולאחר מכן משחזרים את האפליקציה מהרשימה 'לאחרונה'.
  • בגלל באג בגרסאות קודמות של Android, המערכת לא סימנה כהפרה של מצב קפדני את הכתיבה ליציאת TCP בשרשור הראשי. מערכת Android 7.0 מתקנת את הבאג הזה. אפליקציות שמציגות את ההתנהגות הזו גורמות עכשיו להפעלת android.os.NetworkOnMainThreadException. באופן כללי, לא מומלץ לבצע פעולות רשת ב-thread הראשי, כי בדרך כלל יש להן זמן אחזור ארוך שגורם למקרי ANR ולתנודות בתנועה.
  • כברירת מחדל, שיטות משפחת Debug.startMethodTracing() שומרות עכשיו את הפלט בספרייה הספציפית לחבילה באחסון המשותף, במקום ברמה העליונה של כרטיס ה-SD. כלומר, אפליקציות כבר לא צריכות לבקש את ההרשאה WRITE_EXTERNAL_STORAGE כדי להשתמש בממשקי ה-API האלה.
  • ממשקי API רבים של פלטפורמות התחילו לבדוק אם נשלחים עומסי נתונים גדולים בעסקאות Binder, והמערכת מתחילה להחזיר שוב את השגיאה TransactionTooLargeExceptions בתור RuntimeExceptions, במקום להשתיק אותן או לתעד אותן ביומן. דוגמה נפוצה לכך היא אחסון של יותר מדי נתונים ב-Activity.onSaveInstanceState(), שגורם ל-ActivityThread.StopInfo להפעיל RuntimeException כשהאפליקציה מטרגטת ל-Android 7.0.
  • אם אפליקציה מפרסמת משימות Runnable ל-View, וה-View לא מצורף לחלון, המערכת תוסיף את המשימה Runnable לתור עם ה-View. המשימה Runnable לא תבוצע עד שה-View ישויך לחלון. ההתנהגות הזו מתקנת את הבאגים הבאים:
    • אם אפליקציה מפרסמת View משרשור שאינו שרשור ממשק המשתמש של החלון המיועד, יכול להיות שה-Runnable יפעל בשרשור הלא נכון כתוצאה מכך.
    • אם המשימה Runnable פורסמה בשרשור שאינו שרשור של לולאה, האפליקציה עלולה לחשוף את המשימה Runnable.
  • אם אפליקציה ב-Android 7.0 עם ההרשאה DELETE_PACKAGES מנסה למחוק חבילה, אבל אפליקציה אחרת הייתה זו שהתקינה את החבילה, המערכת דורשת אישור מהמשתמש. בתרחיש כזה, סטטוס החזרה של אפליקציות צריך להיות STATUS_PENDING_USER_ACTION כשמפעילים את PackageInstaller.uninstall().
  • ספק ה-JCA שנקרא Crypto הוצא משימוש, כי האלגוריתם היחיד שלו, SHA1PRNG, חלש מבחינה קריפטוגרפית. אפליקציות לא יכולות יותר להשתמש ב-SHA1PRNG כדי להפיק מפתחות (באופן לא מאובטח), כי הספק הזה כבר לא זמין. למידע נוסף, אפשר לעיין בפוסט בבלוג Security "Crypto" provider deprecated in Android N.