SYSTEM 사용자의 패키지 삭제

이 도움말에서는 SYSTEM 사용자에 필요하지 않은 패키지를 식별하고 삭제하여 성능을 개선하는 방법을 설명합니다.

불필요한 패키지 사용 중지

Automotive에서 SYSTEM 사용자는 헤드리스입니다. 즉, SYSTEM 사용자는 사람이 사용하거나 직접 액세스하기 위한 것이 아닙니다. 따라서 많은 앱과 서비스는 SYSTEM 사용자에서 실행할 필요가 없으며 성능 향상을 위해 사용 중지할 수 있습니다. 따라서 SYSTEM 사용자(User 0)의 불필요한 앱을 삭제하는 옵션이 제공됩니다.

이 도움말에서는 두 가지 유형의 사용자를 설명합니다.

  • SYSTEM. 항상 User 0입니다.
  • FULL. 사람(SYSTEM이 아닌 사용자)이 사용하기 위한 사용자로, User 10 이상입니다.

Android 11

Android 11에서는 config_userTypePackageWhitelistMode 구성을 변경합니다. 플래그를 결합할 수 있습니다. 이 경우 51 더하기 4와 같습니다(플래그 14의 결합).

  0  - disable whitelist (install all system packages; no logging)
  1  - enforce (only install system packages if they are whitelisted)
  2  - log (log non-whitelisted packages)
  4  - any package not mentioned in the whitelist file is implicitly whitelisted on all users
  8  - same as 4, but just for the SYSTEM user
  16 - ignore OTAs (don't install system packages during OTAs)
  Common scenarios:
  - to enable feature (fully enforced) for a complete allowlist: 1
  - to enable feature for an incomplete allowlist (so use implicit allowlist mode): 5
  - to enable feature but implicitly allowlist for SYSTEM user to ease local development: 9
  - to disable feature completely if it had never been enabled: 16
  - to henceforth disable feature and try to undo its previous effects: 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에서 패키지 사용 중지 기능을 구성하려면 다음을 실행하세요.

  1. frameworks/base/core/res/res/values/config.xml에서 config_systemUserPackagesBlacklistSupported 구성을 오버레이하고 true로 설정합니다. 기능이 사용 설정되면 기본적으로 모든 패키지가 SYSTEM 사용자와 FULL 사용자에 모두 설치되어야 합니다.
  2. SYSTEM 사용자에 사용 중지해야 하는 패키지를 나열하는 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

전제

SYSTEM 사용자에 패키지를 설치해야 하는지 확인하려면 프로젝트 소스의 루트에서 패키지의 AndroidManifest.xml 파일을 검사합니다. 이 파일에는 애플리케이션의 속성과 앱의 구성요소(모든 활동, 서비스, broadcast receiver, 콘텐츠 제공자 등)가 포함되어 있습니다. 자세한 내용은 앱 매니페스트 개요를 참고하세요.

패키지 워크플로 사용 중지

그림 1. 패키지 워크플로 사용 중지

레벨 1. 애플리케이션 수준

1. 앱(또는 앱 구성요소)이 싱글톤으로 선언되었는지 확인

애플리케이션이 싱글톤이면 시스템은 SYSTEM 사용자에서만 앱을 인스턴스화합니다. 앱은 멀티 사용자 인식 앱이었을 수 있습니다. 멀티 사용자 인식 앱에 관한 자세한 내용은 멀티 사용자 인식 앱 빌드를 참고하세요.

  1. Android 매니페스트에서 android:singleUser="true"를 확인합니다.
  2. true이면 허용 목록에 추가합니다. SYSTEM 사용자에 필요합니다.
  3. false이면 계속 진행합니다. 삭제하기 전에 다른 기준을 확인합니다.

2. 앱에 보호된 저장소 액세스가 필요한지 확인

많은 시스템 부팅 서비스는 사용자 인증 정보 암호화(CE) 저장소 대신 기기 암호화(DE) 저장소에 종종 의존합니다. 또한 직접 부팅을 인식하는 시스템 애플리케이션도 기기 암호화 저장소에 의존합니다. 직접 부팅 인식 앱에 관한 자세한 내용은 시스템 애플리케이션에서 직접 부팅 지원을 참고하세요.

  1. Android 매니페스트에서 다양한 시스템 부팅 서비스에 필요한 android:defaultToDeviceProtectedStorage="true"를 확인합니다.
  2. true이면 허용 목록에 추가합니다.
  3. false이면 계속 진행합니다.

레벨 2. 애플리케이션 구성요소

활동

활동에 관한 자세한 내용은 활동 소개를 참고하세요.

a. 앱에 활동만 포함되어 있는지 확인

활동은 사용자 인터페이스를 중심으로 합니다. SYSTEM 사용자는 Automotive에서 헤드리스이므로 사람이 SYSTEM 사용자와 상호작용해서는 안 됩니다. 따라서 앱에 활동만 포함된 경우 앱은 SYSTEM 사용자와 관련 없을 가능성이 높습니다.

우선순위와 특수 권한을 확인합니다.

  1. 라면 SYSTEM 사용자에 필요할 수 있습니다.
  2. 아니요라면 SYSTEM 사용자를 위한 허용 목록에 추가하지 않습니다.

예를 들어 호환성 테스트 모음(CTS)(com.android.cts.priv.ctsshim)에는 활동만 포함되고 활동은 인텐트 필터를 테스트하기 위해 정의됩니다. 그러나 높은 권한이 있으므로 테스트용으로 SYSTEM 사용자를 위해 설치해야 합니다.

서비스

서비스에 관한 자세한 내용은 서비스 개요를 참고하세요.

b. 서비스가 비공개로 선언되고 다른 애플리케이션에서 액세스할 수 없는지 확인

서비스가 비공개로 선언되면 다른 패키지는 이 서비스를 사용하지 않습니다. android:exported="false"를 찾습니다. 서비스가 비공개로 선언되거나 다른 애플리케이션에서 액세스할 수 없으면 다른 애플리케이션에서 바인드할 수 없습니다. 따라서 아래의 C단계와 D단계는 관련이 없습니다. 결국 이 구성요소는 서비스가 SYSTEM 사용자에 필요한지에 관한 추가 힌트를 제공하지 않습니다.

  1. 라면 다음 구성요소를 확인합니다.
  2. 아니요라면 이 구성요소를 계속 확인합니다.

c. SYSTEM 사용자에 설치된 애플리케이션이 이 서비스에 바인드될 수 있는지 확인

레벨 1에서 허용 목록에 있는 패키지를 확인하고 패키지가 바인드된 서비스를 식별합니다. 이 서비스의 인텐트 필터와 다른 패키지의 startService에서 추적합니다.

이 서비스가 SYSTEM 사용자에 설치된 앱에 바인드된 경우(예: com.android.car.companiondevicesupport가 SYSTEM 사용자에서 실행되도록 허용 목록에 추가됨) 서비스를 허용 목록에 추가합니다.

  1. 라면 허용 목록에 추가합니다.
  2. 아니요라면 이 구성요소를 계속 확인합니다.

d. 서비스가 다른 애플리케이션에서 바인드되고 포그라운드에서 실행되도록 선언되었는지 확인

startForeground를 찾습니다. 즉, 사람들이 포그라운드에서 앱과 상호작용한다는 의미입니다. 대부분의 경우 이 서비스는 SYSTEM 사용자에 필요하지 않으며 허용 목록에 추가하지 않아도 됩니다.

  1. 라면 허용 목록에 추가하지 않습니다.
  2. 아니요라면 다음 구성요소를 계속 확인합니다.

e. 서비스가 시스템 프로세스에서 실행되도록 정의되었는지 확인

AndroidManifest에서 android:process="system"을 찾습니다.
서비스가 의도적으로 시스템 프로세스에서 실행되도록 정의되면 시스템 서비스와 동일한 프로세스에서 명시적으로 실행되고 SYSTEM 사용자에서 실행되도록 허용 목록에 추가되어야 한다는 것을 의미합니다. Android의 메모리 할당 설계의 일부로서, 시스템 서비스는 마지막으로 종료되는 프로세스의 하나이며 이는 이러한 속성으로 정의된 서비스의 중요성을 나타냅니다. Android의 메모리 할당 설계에 관한 자세한 내용은 로우 메모리 킬러를 참고하세요.

  1. 라면 허용 목록에 추가하지 않습니다.
  2. 아니요라면 다른 구성요소를 계속 확인합니다.

예를 들어 패키지 com.android.networkstack.inprocessandroid:process="system" 태그가 있는 RegularMaintenanceJobService를 포함하고 있으므로 허용 목록에 추가해야 합니다.

콘텐츠 제공자

콘텐츠 제공자에 관한 자세한 내용은 콘텐츠 제공자를 참고하세요.

f. SYSTEM 사용자에 설치된 애플리케이션이 이 제공자에 의존하는지 확인

레벨 1에서 허용 목록에 있는 패키지를 확인하고 패키지가 의존하는 제공자를 확인합니다. SYSTEM 사용자에서 실행되는 애플리케이션(예: com.android.car.companiondevicesupport는 SYSTEM 사용자에서 실행되도록 허용 목록에 추가됨)이 이 콘텐츠 제공자에 의존한다면 콘텐츠 제공자도 허용 목록에 추가해야 합니다.

  1. 라면 허용 목록에 추가합니다.
  2. 아니요라면 허용 목록에 추가하지 않습니다.

예를 들어 싱글톤 제공자(SystemActionsContentProvider, ManagedProvisioningActionsContentProvider)를 포함하는 com.android.car.EXAMPLE은 SYSTEM 사용자를 위해 허용 목록에 추가되어야 합니다. 그런 다음 com.android.car.EXAMPLEWebViewFactoryProviderandroid.webkit에 의존하면 com.android.webviewandroid.webkit을 로드한다는 점을 감안하여 SYSTEM 사용자를 위해 허용 목록에 추가되어야 합니다.

샘플 패키지 살펴보기

다음 예는 패키지의 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>