本頁面說明如何找出系統使用者不需要的套件,並將其移除,以改善效能。
停用不必要的套件
在 Automotive 中,系統使用者是無頭,也就是說系統使用者不應由人類使用或直接存取。因此,許多應用程式和服務不需要在系統使用者中執行,而且可以停用來改善效能。因此,我們提供一個選項,可為系統使用者 (使用者 0) 移除不必要的應用程式。
本頁將討論兩種使用者:
- SYSTEM:一律使用 User 0
- FULL。使用者 (非系統使用者) 是指人類使用者,年齡須滿 10 歲
Android 11
在 Android 11 中,變更 config_userTypePackageWhitelistMode
設定。標記可以合併。在本例中,5
等同於 1
加上 4
(標記 1
和 4
的組合)。
檢舉 | 說明 |
---|---|
0 |
停用許可清單。安裝所有系統套件,但不記錄。 |
1 |
強制執行。僅在系統套件列入許可清單時安裝。 |
2 |
記錄未加入許可清單的套件。 |
4 |
凡是許可清單檔案未提及的套件,都會對所有使用者隱含許可。 |
8 |
與 4 相同,適用於系統使用者。 |
16 |
忽略網路旅行社。請勿在 OTA 期間安裝系統套件。 |
請參考以下常見情境:
- 如要為完整的許可清單啟用功能,請使用
1
(完全強制執行) - 如要為不完整的許可清單啟用功能,
5
- 如要為
SYSTEM
使用者啟用功能,以便進行本機開發,請使用9
(隱含許可清單) - 如要停用某項功能,就好像從未啟用這項功能一樣,
16
- 如要停用功能並復原先前的所有效果,請按下
0
在裝置的 sysconfig
目錄中安裝 XML 檔案 (這個目錄包含用於建構裝置系統映像檔的 makefile (.mk
))。為 XML 檔案命名時,請加入在版本中定義套件的所在位置,例如 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 中設定這項功能,請按照下列步驟操作:
- 重疊
frameworks/base/core/res/res/values/config.xml
中的config_systemUserPackagesBlacklistSupported
設定,並將其設為true
。開啟這項功能後,系統使用者和 FULL 使用者都應預設安裝所有套件。 - 建立
config.xml
檔案,列出應為系統使用者停用的套件,例如:<config> <!-- This package will be uninstalled for the system user --> <system-user-blacklisted-app package="com.google.car.calendar" /> </config>
- 在
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
檔案,包括應用程式屬性和應用程式元件 (包括所有活動、服務、廣播接收器和內容供應器)。詳情請參閱「應用程式資訊清單總覽」。
圖 1. 停用套件工作流程。
等級 1,應用程式層級
1. 檢查應用程式 (或應用程式元件) 是否宣告為單例
如果應用程式是單例,系統只會在系統使用者中例項化應用程式。應用程式很可能會是多用戶感知應用程式。如要進一步瞭解多用戶感知應用程式,請參閱「建構多用戶感知應用程式」。
- 檢查 Android 資訊清單中的
android:singleUser="true"
。 - 如果是
true
,則為許可清單。系統使用者需要的資訊。 - 如果是
false
,請繼續操作。請先檢查其他條件再移除。
2. 檢查應用程式是否需要受保護的儲存空間存取權
許多系統啟動服務通常會使用裝置加密 (DE) 儲存空間,而非憑證加密 (CE) 儲存空間。此外,直接啟動感知的系統應用程式也需要使用裝置加密儲存空間。如要進一步瞭解直接啟動感知應用程式,請參閱「在系統應用程式中支援直接啟動」。
- 檢查 Android 資訊清單中的
android:defaultToDeviceProtectedStorage="true"
,許多系統啟動服務都需要這個項目。 - 如果是
true
,則加入許可清單。 - 如果是
false
,請繼續。
等級 2,應用程式元件
活動
如要進一步瞭解活動,請參閱「活動簡介」。
a. 檢查應用程式是否只包含活動
活動是以使用者介面為導向。由於 Automotive 中的系統使用者是無頭的,因此不應有任何人與系統使用者互動。因此,如果應用程式只包含活動,就很可能與系統使用者無關。
檢查優先順序和特殊權限:
- 如果為「是」,系統使用者可能需要使用者名稱。
- 如果為「否」,則不要將系統使用者加入許可清單。
舉例來說,相容性測試套件 (CTS) (com.android.cts.priv.ctsshim
) 只包含活動,而活動則是用於測試意圖篩選器。不過,由於 CTS 具有較高的權限,因此需要為系統使用者安裝,以便進行測試。
服務
如要進一步瞭解服務,請參閱「服務總覽」。
b. 檢查服務是否已宣告為私人,且無法從其他應用程式存取
如果服務宣告為private,其他套件就不會使用該服務。尋找 android:exported="false"
。如果服務宣告為私人,或無法從其他應用程式存取,則無法由其他應用程式繫結。因此,下方的步驟 c 和步驟 d 與此無關。因此,這個元件不會提供更多提示,說明系統使用者是否需要這項服務。
- 如果是「是」,請檢查下一個元件。
- 如果是「否」,請繼續檢查這個元件。
c. 檢查系統使用者安裝的應用程式是否可能繫結至這項服務
檢查第 1 級的許可清單套件,並找出這些套件綁定的服務。從此服務中的意圖篩選器和其他套件中的 startService
進行追蹤。
如果這項服務已繫結至系統使用者安裝的應用程式 (例如,com.android.car.companiondevicesupport
已列入許可清單,可在系統使用者中執行),請將服務列入許可清單:
- 如果答案為「是」,請加入許可清單。
- 如果是「否」,請繼續檢查這個元件。
d. 檢查服務是否已從其他應用程式繫結,並宣告要在前景執行
尋找 startForeground
。也就是說,使用者會在前景與應用程式互動。系統使用者很可能不需要這項服務,因此不需要將其列入許可清單:
- 如果是「是」,請不要加入許可清單。
- 如果是「否」,請繼續檢查下一個元件。
e. 檢查服務是否已定義為在系統程序中執行
在 AndroidManifest 檔案中尋找 android:process="system"
。如果服務是刻意定義為在系統程序中執行,則會與系統服務在相同程序中執行,並應列入許可清單,以便在系統使用者中執行。在 Android 的記憶體分配設計中,系統服務是最後終止的程序之一,這表示使用此屬性定義的服務具有重要性。如要進一步瞭解 Android 的記憶體配置設計,請參閱「低記憶體殺手」。
- 如果是「是」,請不要加入許可清單。
- 如果是「否」,請繼續檢查其他元件。
舉例來說,套件 com.android.networkstack.inprocess
必須列入許可清單,因為它包含 RegularMaintenanceJobService
,而 RegularMaintenanceJobService
具有 android:process="system"
標記。
內容供應者
如要進一步瞭解內容供應器,請參閱「內容供應器」。
f. 檢查系統使用者安裝的應用程式是否依賴這個供應器
檢查第 1 級中是否有許可清單中的套件,並查看這些套件依賴哪些供應商。如果應用程式在系統使用者中執行 (例如 com.android.car.companiondevicesupport
已列入允許清單,可在系統使用者中執行),且依賴這個內容供應器,請務必將這個內容供應器列入允許清單。
- 如果答案為「是」,請加入許可清單。
- 如果是「否」,則不要將其加入許可清單。
舉例來說,如果 com.android.car.EXAMPLE
包含單例供應器 (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>