시스템 사용자를 위한 패키지 삭제

이 페이지에서는 시스템 사용자에게 필요하지 않은 패키지를 식별하고 삭제하여 성능을 개선하는 방법을 설명합니다.

불필요한 패키지 사용 중지

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

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

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

Android 11

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

플래그 설명
0 허용 목록을 사용 중지합니다. 모든 시스템 패키지를 설치합니다. 로깅하지 않습니다.
1 실행합니다. 허용 목록에 추가된 시스템 패키지만 설치합니다.
2 허용 목록에 없는 패키지만 로깅합니다.
4 허용 목록 파일에 언급되지 않은 패키지는 암시적으로 모든 사용자에 대해 허용 목록에 추가된 것으로 간주합니다.
8 시스템 사용자에 대해 4 코드와 같이 적용됩니다.
16 OTA를 무시합니다. 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에서 이 기능을 구성하려면 다음을 실행하세요.

  1. frameworks/base/core/res/res/values/config.xml에서 config_systemUserPackagesBlacklistSupported 구성을 오버레이하고 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 파일을 검사합니다. 여기에는 앱의 속성과 앱의 구성요소(모든 활동, 서비스, Broadcast Receiver, 콘텐츠 제공자 포함)가 포함됩니다. 자세한 내용은 앱 매니페스트 개요를 참고하세요.

패키지 워크플로 사용 중지

그림 1. 패키지 워크플로를 사용 중지합니다.

레벨 1. 앱 수준

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

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

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

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

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

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

레벨 2. 앱 구성요소

활동

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

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

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

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

  1. 인 경우 시스템 사용자에게 필요할 수 있습니다.
  2. 아니요라면 시스템 사용자를 위한 허용 목록에 추가하지 않습니다.

예를 들어 호환성 테스트 모음(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.inprocessandroid:process="system" 태그가 있는 RegularMaintenanceJobService를 포함하고 있으므로 허용 목록에 추가해야 합니다.

콘텐츠 제공자

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

f. 시스템 사용자에 설치된 앱이 이 제공자에 의존하는지 확인

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

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

예를 들어 싱글톤 제공자 (SystemActionsContentProviderManagedProvisioningActionsContentProvider)를 포함하는 com.android.car.EXAMPLE은 시스템 사용자를 위해 허용 목록에 추가되어야 합니다. 그런 다음 com.android.car.EXAMPLEWebViewFactoryProviderandroid.webkit에 의존하면 com.android.webviewandroid.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>