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

בדף הזה נסביר איך לשפר את הביצועים על ידי זיהוי והסרה של חבילות שלא נחוצות למשתמש המערכת.

השבתת חבילות לא נחוצות

ב-Automotive, משתמש המערכת הוא headless, כלומר משתמש המערכת לא מיועד לשימוש על ידי בני אדם או לגישה ישירה שלהם. כתוצאה מכך, אין צורך להריץ אפליקציות ושירותים רבים בתור משתמש המערכת, ואפשר להשבית אותם כדי לשפר את הביצועים. לכן יש אפשרות להסיר אפליקציות מיותרות למשתמש המערכת (משתמש 0).

בדף הזה מוצגים שני סוגי משתמשים:

  • SYSTEM. תמיד משתמש 0
  • FULL. משתמש שמיועד לשימוש של משתמש אנושי (משתמש שאינו מערכת), משתמש מגיל 10 ומעלה

Android 11

ב-Android 11, משנים את ההגדרה של config_userTypePackageWhitelistMode. אפשר לשלב סימונים. במקרה כזה, הערך של 5 שווה ל-1 ‎+ 4 (שילוב של הדגלים 1 ו-4).

סימון תיאור
0 השבתת רשימת ההיתרים. התקנת כל חבילות המערכת, ללא רישום ביומן.
1 אכיפה. התקנה של חבילות מערכת רק אם הן נמצאות ברשימת ההיתרים.
2 רישום ביומן של חבילות שלא נכללות ברשימת ההיתרים.
4 חבילה שלא מוזכרת בקובץ רשימת ההיתרים מתווספת באופן מפורש לרשימת ההיתרים של כל המשתמשים.
8 זהה ל-4, למשתמש המערכת.
16 התעלמות מעדכוני OTA. אין להתקין חבילות מערכת במהלך זמני OTA.

כדאי להביא בחשבון את התרחישים הנפוצים הבאים:

  • כדי להפעיל תכונה לרשימת היתרים מלאה, 1 (אכיפה מלאה)
  • כדי להפעיל תכונה לרשימת היתרים שלא הושלמה, 5
  • כדי להפעיל תכונה למשתמש SYSTEM כדי להקל על הפיתוח המקומי, 9 (רשימת היתרים משתמעת)
  • כדי להשבית תכונה כאילו היא מעולם לא הופעלה, 16
  • כדי להשבית תכונה ולבטל את כל האפקטים הקודמים, 0

מתקינים את קובץ ה-XML בספרייה sysconfig של המכשיר (זו אותה הספרייה שמכילה את getfile (.mk) ששימשה ליצירת קובץ אימג' של המערכת של המכשיר). כשנותנים שם לקובץ ה-XML, צריך לכלול את המיקום שבו החבילה מוגדרת ב-build, לדוגמה, preinstalled-packages-product-car-CAR_PRODUCT_NAME.xml.

<!- this package will be installed for both FULL and SYSTEM user -->
    <install-in-user-type package="com.android.bluetooth"->
        <install-in user-type="FULL" /->
        <install-in user-type="SYSTEM" /->
    </install-in-user-type->

<!- this package will only be installed for both FULL user -->
    <install-in-user-type package="com.android.car.calendar"->
        <install-in user-type="FULL" >
    </install-in-user-type->

Android 9 ו-Android 10

כדי להגדיר את התכונה הזו ב-Android 9 וב-Android 10:

  1. מעבירים את קובץ התצורה config_systemUserPackagesBlacklistSupported מ-frameworks/base/core/res/res/values/config.xml ומגדירים אותו כ-true. כשהתכונה מופעלת, כברירת מחדל כל החבילות אמורות להיות מותקנות גם למשתמש המערכת וגם למשתמש עם הרשאת FULL.
  2. יוצרים רשימת קבצים config.xml שכוללת את החבילות שצריך להשבית עבור משתמש המערכת, לדוגמה:
    <config>
        <!-- This package will be uninstalled for the system user -->
        <system-user-blacklisted-app package="com.google.car.calendar" />
    </config>
  3. מוסיפים שורה לקובץ device.mk כדי להעתיק את הקובץ לתיקיית היעד system/etc/sysconfig/ במכשיר, לדוגמה:
    PRODUCT_COPY_FILES += <full path to the config file>:system/etc/sysconfig/<new denylist config file>.xml

אימות התוצאה

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

$ adb shell dumpsys user | grep PACKAGE_SUBSTRING
$ adb shell pm list packages --user USER_ID PACKAGE_SUBSTRING
$ adb shell cmd user report-system-user-package-whitelist-problems

שם בניין

כדי לקבוע אם צריך להתקין חבילה אצל משתמש המערכת, צריך לבדוק את קובץ AndroidManifest.xml של החבילה שנמצא ברמה הבסיסית (root) של מקור הפרויקט, כולל מאפייני האפליקציה ורכיבי האפליקציה, שכוללים את כל הפעילויות, השירותים, מקלטי השידור וספקי התוכן. מידע נוסף זמין במאמר סקירה כללית על מניפסט של אפליקציה.

השבתת תהליך העבודה של חבילות

איור 1. משביתים את תהליך העבודה של חבילות.

רמה 1, ברמת האפליקציה

1. בדיקה אם האפליקציה (או רכיבי האפליקציה) מוגדרים כ-singleton

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

  1. כדאי לבדוק את המניפסט של Android של android:singleUser="true".
  2. אם true, רשימת ההיתרים. נדרשת למשתמש המערכת.
  3. אם הערך שלו הוא false, המשך. לפני ההסרה, כדאי לבדוק קריטריונים אחרים.

2. בודקים אם לאפליקציה נדרשת גישה לאחסון מוגן

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

  1. בודקים את המניפסט של Android כדי למצוא את android:defaultToDeviceProtectedStorage="true", שנחוץ למספר רב של שירותי אתחול המערכת.
  2. אם true, רשימת ההיתרים.
  3. אם הערך הוא false, ממשיכים.

רמה 2, רכיבי האפליקציה

פעילויות

למידע נוסף על פעילויות, ראו מבוא לפעילויות.

א. בודקים אם האפליקציה מכילה רק פעילויות

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

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

  1. אם כן, יכול להיות שיהיה צורך במשתמש המערכת.
  2. אם האפשרות לא, אין להוסיף את משתמש המערכת לרשימת ההיתרים.

לדוגמה, חבילה לבדיקות תאימות (CTS) (com.android.cts.priv.ctsshim) מכילה רק פעילויות, והפעילויות מוגדרות לבדיקה של מסנני כוונת החיפוש. עם זאת, מאחר של-CTS יש הרשאה גבוהה, צריך להתקין אותו עבור משתמש המערכת למטרות בדיקה.

שירות

מידע נוסף על שירותים זמין במאמר סקירה כללית על שירותים.

ב. בודקים אם השירות הוגדר כפרטי ואין גישה אליו מאפליקציות אחרות

אם השירות מוצהר כפרטי, חבילות אחרות לא ישתמשו בשירות. צריך לחפש את android:exported="false". אם השירות מכריז כפרטי או שאי אפשר לגשת אליו מאפליקציות אחרות, אפליקציות אחרות לא יכולות להגביל אותו. לכן, שלב ג ושלב ד שבהמשך לא רלוונטיים. כתוצאה מכך, הרכיב הזה לא יספק יותר רמזים לגבי השאלה אם השירות דרוש למשתמש המערכת.

  • אם התשובה היא כן, בודקים את הרכיב הבא.
  • אם הערך הוא לא, צריך להמשיך לבדוק את הרכיב הזה.

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

בודקים אם יש חבילות ברשימת ההיתרים ברמה 1 ומזהים את השירותים שהן מקושרות אליהם. מעקב אחרי מסנן הכוונה בשירות הזה וב-startService בחבילות אחרות.

אם השירות הזה מקושר לאפליקציות שהותקנו במשתמש המערכת (לדוגמה, com.android.car.companiondevicesupport נכלל ברשימת ההיתרים להפעלה של משתמש המערכת), מוסיפים את השירות לרשימת ההיתרים:

  • אם כן, מוסיפים את האפשרות לרשימת ההיתרים.
  • אם הערך הוא לא, צריך להמשיך לבדוק את הרכיב הזה.

ד. בדיקה אם השירות מקושר מאפליקציות אחרות ומוצהר כפעיל בחזית

מחפשים את startForeground. המשמעות היא שאנשים יצרו אינטראקציה עם האפליקציה בחזית. סביר להניח שהשירות הזה לא נחוץ למשתמש המערכת ואין צורך להוסיף אותו לרשימת ההיתרים:

  • אם כן, אין להוסיף את האפשרות לרשימת ההיתרים.
  • אם התשובה היא לא, ממשיכים לבדוק את הרכיב הבא.

ה. בדיקה אם השירות מוגדר לפעול בתהליך המערכת

בקובץ AndroidManifest, צריך לחפש את android:process="system". אם השירות מוגדר בכוונה לפעול בתהליך המערכת, הוא פועל באותו תהליך כמו שירות המערכת, וצריך להוסיף אותו לרשימת ההיתרים כדי שיפעל בתור משתמש המערכת. כחלק מתכנון הקצאת הזיכרון ב-Android, שירותי המערכת הם חלק מהתהליכים האחרונים שיתופסים. מרמז על החשיבות של שירותים שמוגדרים במאפיין כזה. למידע נוסף על תכנון הקצאת הזיכרון ב-Android, ראו הסרת משימות עם זיכרון נמוך.

  • אם כן, לא מוסיפים לרשימת ההיתרים.
  • אם התשובה היא לא, ממשיכים לבדוק רכיבים אחרים.

לדוגמה, החבילה com.android.networkstack.inprocess חייבת להיכלל ברשימת ההיתרים כי היא מכילה את RegularMaintenanceJobService, עם התג android:process="system".

ספק תוכן

מידע נוסף על ספקי תוכן זמין במאמר ספקי תוכן.

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

אפשר לבדוק אם יש חבילות שנמצאות ברשימת ההיתרים ברמה 1 ולבדוק באילו ספקים הן תלויות. אם אפליקציה שפועלת בתור משתמש המערכת (לדוגמה, com.android.car.companiondevicesupport נמצאת ברשימת ההיתרים לפעול בתור משתמש המערכת) ותלויה בספק התוכן הזה, צריך לוודא שגם ספק התוכן הזה נמצא ברשימת ההיתרים.

  1. אם כן, מוסיפים את האפשרות לרשימת ההיתרים.
  2. אם לא, לא מוסיפים לרשימת ההיתרים.

לדוגמה, אם הספק com.android.car.EXAMPLE מכיל ספקים של singleton (SystemActionsContentProvider ו-ManagedProvisioningActionsContentProvider), הוא צריך להיכלל ברשימת ההיתרים של משתמש המערכת. לאחר מכן, אם com.android.car.EXAMPLE תלוי בערך android.webkit של WebViewFactoryProvider, אז com.android.webview חייב להיכלל ברשימת ההיתרים של משתמש המערכת כי הוא טוען את android.webkit.

הדרכה לדוגמה על חבילות

הדוגמה הבאה מראה איך להעריך את הערך של AndroidManifest.xml של חבילה:

<?xml version="1.0" encoding="utf-8"?>
<!-- 1. Search in the entire manifest for singleUser attribute.
No. Move to step 2 -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.providers.calendar"
        android:sharedUserId="android.uid.calendar">
    We can ignore the entire permission section
    <uses-permission android:name="android.permission.READ_CALENDAR" />
    ...
    <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
<!-- 2. Look for defaultToDeviceProtectedStorage in application's attribute.
No. Continue evaluating app components. -->
    <application android:label="@string/calendar_storage"
                 android:allowBackup="false"
                 android:icon="@drawable/app_icon"
                 android:usesCleartextTraffic="false">
<!-- a. Contain only activities?
No. Continue to evaluate components other than activities. -->
        <provider android:name="CalendarProvider2" android:authorities="com.android.calendar"
                <!-- b. Is this component exported?
                Yes. Continue evaluating this component.
                f. App on u0 might depend on this? Search for CalendarProvider2 in dumpsys, shows ContentProviderRecord{b710923 u0 com.android.providers.calendar/.CalendarProvider2}
                Yes. Whitelist for system user. -->
                android:label="@string/provider_label"
                android:multiprocess="false"
                android:exported="true"
                android:readPermission="android.permission.READ_CALENDAR"
                android:writePermission="android.permission.WRITE_CALENDAR" />

<activity android:name="CalendarContentProviderTests" android:label="Calendar Content Provider" android:exported="false"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.UNIT_TEST" /> </intent-filter> </activity> <!-- Not service/content provider. Ignore. --> <receiver android:name="CalendarProviderBroadcastReceiver" android:exported="false"> <intent-filter> <action android:name="com.android.providers.calendar.intent.CalendarProvider2"/> <category android:name="com.android.providers.calendar"/> </intent-filter> <intent-filter> <action android:name="android.intent.action.EVENT_REMINDER"/> <data android:scheme="content" /> </intent-filter> </receiver> <service android:name="CalendarProviderIntentService"/> </application> </manifest>