刪除系統使用者的軟體包

本文介紹如何透過識別和刪除系統使用者不需要的套件來提高效能。

禁用不必要的包

在汽車領域,系統使用者是無頭的,這意味著系統使用者不適合由人類使用或直接存取。因此,許多應用程式和服務不需要在系統用戶中運行,並且可以停用以提高效能。因此,提供了一個選項來為系統使用者(使用者0)刪除不必要的應用程式。

在此頁面上,討論了兩種類型的使用者:

  • 系統。始終為用戶 0
  • 滿的。旨在由人類(非系統用戶)使用的用戶,用戶 10+

安卓11

在 Android 11 中,您可以變更設定config_userTypePackageWhitelistMode 。標誌可以組合。在本例中, 5等於14 (標誌14的組合)。

旗幟描述
0禁用白名單。安裝所有系統套件;沒有日誌記錄。
1執行。僅當系統軟體包列入許可名單時才安裝它們。
2記錄非允許清單中的包。
4允許清單檔案中未提及的任何套件都會隱式列入所有使用者的允許清單中。
8對於系統用戶,與4相同。
16忽略 OTA。請勿在 OTA 期間安裝系統軟體套件。
考慮這些常見場景。
  • 若要啟用完整白名單的功能, 1完全強制
  • 若要啟用不完整白名單的功能, 5
  • 若要為SYSTEM使用者啟用一項功能以簡化本機開發, 9隱式白名單
  • 要停用某項功能,就好像它從未啟用過一樣, 16
  • 若要停用某項功能並撤銷所有先前的效果, 0

確保將 XML 檔案安裝在裝置的sysconfig目錄中(該目錄包含用於建置裝置系統映像的 makefile (`.mk`))。命名 XML 檔案時,請包含在 build.gradle 檔案中定義包的位置。例如, 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->

安卓 9 和安卓 10

要在 Android 9 和 Android 10 中設定此功能:

  1. 覆寫frameworks/base/core/res/res/values/config.xml中的config_systemUserPackagesBlacklistSupported配置並將其設為true 。啟用此功能後,預設情況下,應為系統使用者和完整使用者安裝所有軟體包。
  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文件,包括應用程式的屬性和應用程式的元件,其中包括所有活動、服務、廣播接收器、和內容提供者。要了解更多信息,請參閱應用程式清單概述

禁用套件工作流程

圖 1.禁用套件工作流程

1 級,應用程式級別

1. 檢查應用程式(或應用程式元件)是否聲明為單例

如果應用程式是單例,系統將僅在系統使用者中實例化該應用程式。該應用程式可能旨在成為一個多用戶感知的應用程式。要了解有關多用戶感知應用程式的更多信息,請參閱建立多用戶感知應用程式

  1. 檢查 Android 清單中的android:singleUser="true"
  2. 如果true ,則列入白名單。系統用戶需要。
  3. 如果為false ,則繼續。刪除前檢查其他標準。

2. 檢查應用程式是否需要受保護的儲存存取

許多系統啟動服務通常依賴裝置加密 (DE) 存儲,而不是憑證加密 (CE) 儲存。此外,直接啟動感知的系統應用程式也依賴裝置加密儲存。要了解有關直接啟動感知應用程式的更多信息,請參閱支援系統應用程式中的直接啟動

  1. 檢查 Android 清單中的android:defaultToDeviceProtectedStorage="true" ,這是眾多系統啟動服務所必需的。
  2. 如果true ,則列入白名單。
  3. 如果為false ,則繼續。

2 級,應用程式元件

活動

要了解有關活動的更多信息,請參閱活動簡介

A。檢查應用程式是否僅包含活動

活動是面向使用者介面的。由於系統使用者在汽車領域是無頭的,因此任何人都不應該與系統使用者互動。因此,如果應用程式僅包含活動,則該應用程式很可能與系統使用者無關。

檢查優先權和特殊權限。

  1. 如果,系統使用者可能需要。
  2. 如果「否」 ,則不將系統使用者列入白名單。

例如,相容性測試套件 (CTS) ( com.android.cts.priv.ctsshim ) 僅包含活動,且活動被定義為測試意圖過濾器。但由於它具有較高的權限,因此需要為系統使用者安裝以進行測試。

服務

要了解有關服務的更多信息,請參閱服務概述

b.檢查服務是否被聲明為私有且無法從其他應用程式存取

如果服務被宣告為private ,其他套件將不會使用該服務。尋找android:exported="false" 。如果該服務被聲明為私有或無法從其他應用程式訪問,則它不能被其他應用程式綁定。因此,以下的步驟C和步驟D是無關緊要的。結果,該元件不會提供關於系統使用者是否需要該服務的更多提示。

  1. 如果,請檢查下一個組件。
  2. 如果,請繼續檢查該組件。

C。檢查系統使用者中安裝的應用程式是否可以綁定到此服務

檢查等級 1 中是否有列入白名單的程式包並確定​​它們所綁定的服務。從該服務中的 Intent 過濾器和其他套件中的startService進行追蹤。

如果此服務綁定到系統使用者中安裝的應用程式(例如, com.android.car.companiondevicesupport被列入白名單以在系統使用者中運行),則將該服務列入白名單。

  1. 如果,則列入白名單。
  2. 如果,請繼續檢查該組件。

d.檢查服務是否與其他應用程式綁定並聲明在前台運行

尋找startForeground 。這意味著人們將在前台與應用程式互動。最有可能的是,系統使用者不需要此服務,並且不需要列入許可名單。

  1. 如果,則不要列入許可名單。
  2. 如果,請繼續檢查下一個組件。

e.檢查服務是否定義為在系統進程中執行

在 AndroidManifest 中,尋找android:process="system"
如果服務被有意定義為在系統進程中運行,則表示它明確將在與系統服務相同的進程中運行,並且應該被列入白名單以在系統使用者中運行。作為Android記憶體分配設計的一部分,系統服務是最後被殺死的過程之一,這意味著使用此類屬性定義的服務的重要性。要了解有關 Android 內存分配設計的更多信息,請參閱低內存殺手

  1. 如果,則不要列入白名單。
  2. 如果,請繼續檢查其他組件。

例如,包裝com.android.networkstack.inprocess必須列入白名單,因為它包含RegularMaintenanceJobService ,該服務具有android:process="system"標籤。

內容提供者

要了解有關內容提供者的更多信息,請參閱內容提供者

F。檢查系統使用者中安裝的應用程式是否依賴該提供者

檢查 1 級中是否有列入白名單的軟體包,並檢查它們依賴哪些提供者。如果在系統使用者中執行的應用程式(例如, com.android.car.companiondevicesupport被列入允許在系統使用者中運行)並且依賴此內容提供程序,則請確保此內容提供者也被列入允許名單。

  1. 如果,則列入白名單。
  2. 如果「否」 ,則不要列入許可名單。

例如,如果com.android.car.EXAMPLE包含單例提供者( SystemActionsContentProviderManagedProvisioningActionsContentProvider ),則應將其列入系統使用者的白名單。然後,如果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>