플래시 메모리 사용량 모니터링

워치독은 `/proc/uid_io/stats` 위치에서 커널에 의해 노출된 UID별 디스크 I/O 통계를 사용하여 모든 앱 및 서비스에서 실행한 디스크 I/O 쓰기의 총량을 추적하는 방식으로 플래시 메모리 사용량을 모니터링합니다. 앱이나 서비스가 디스크 I/O 초과 사용 임곗값을 초과하면 워치독은 앱 또는 서비스에 조치를 취합니다. 디스크 I/O 초과 사용 임곗값과 초과 사용에 대한 조치는 디스크 I/O 초과 사용 구성에 사전 정의되어 있습니다.

초과 사용 임곗값

  • 디스크 I/O 초과 사용 임곗값은 매일 적용됩니다. 즉, 앱/서비스에서 실행한 모든 쓰기 작업이 현재 UTC 달력 날짜가 시작된 이후 집계되고 초과 사용 구성에 정의된 임곗값과 비교하여 확인됩니다.
  • 특정 날짜에 차량이 여러 번 시동될 경우 워치독 모듈은 디스크 I/O 사용 통계를 플래시 메모리에 저장하고 현재 UTC 달력 날짜가 시작된 후부터 이를 집계합니다.

초과 사용 조치

앱이 정의된 디스크 I/O 초과 사용 임곗값을 반복적으로 초과하는 경우 워치독은 초과 사용 구성에 정의된 조치를 실행합니다.

  • 모든 공급업체 앱 및 서비스는 전반적인 시스템 안정성에 중요하므로 디스크 I/O 초과 사용으로 인해 종료되지는 않습니다. 그러나 초과 사용 구성에서는 종료해도 안전한 공급업체 앱 및 서비스 목록을 정의할 수 있습니다.
  • 모든 서드 파티 앱은 종료해도 안전합니다.

앱이나 서비스가 종료해도 안전한 경우 워치독은 앱 구성요소 상태 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED를 사용하여 앱이나 서비스를 사용 중지합니다.

초과 사용 구성

초과 사용 구성에는 디스크 I/O 초과 사용 임곗값과 조치가 포함되어 있습니다. 기본 초과 사용 구성은 시스템 이미지와 공급업체 이미지에 정의되어 있으며 빌드와 함께 제공됩니다. 공급업체는 선택적으로 공급업체 이미지에 공급업체 구성을 포함할 수 있습니다. 공급업체 구성이 제공되지 않는 경우 시스템 구성이 공급업체 앱 및 서비스에도 사용됩니다.

워치독은 CarWatchdogManager를 통해 시스템 API를 노출하므로 공급업체 앱이나 서비스에서 언제든지 공급업체 구성을 업데이트할 수 있습니다.

초과 사용 구성 정의

초과 사용 구성은 시스템, 공급업체, 서드 파티 등 구성요소 유형으로 나뉩니다. OEM은 공급업체 구성요소 구성만 업데이트해야 합니다.

공급업체 구성

공급업체 구성에서는 모든 공급업체 앱과 서비스 그리고 모든 지도와 미디어 앱과 관련해 디스크 I/O 초과 사용 임곗값과 조치가 정의됩니다. 이 구성에는 다음과 같은 구성 필드가 포함됩니다.

  • Vendor package prefixes. 공급업체 파티션에 설치된 모든 패키지는 공급업체 패키지로 간주됩니다. 이러한 패키지 외에도 공급업체는 vendor package prefixes 구성에 패키지 접두사를 추가하여 사전 설치된 패키지를 공급업체 패키지로 분류할 수 있습니다. 이 구성에는 정규 표현식이 허용되지 않습니다.
  • Safe-to-terminate packages. 공급업체는 전체 패키지 이름을 safe-to-terminate packages 구성에 추가하여 안전하게 종료할 수 있는 공급업체 패키지를 지정할 수 있습니다.
  • Application category mappings. 공급업체는 지원되는 두 가지 앱 카테고리인 지도 및 미디어 앱 중 하나에 패키지(서드 파티 패키지 포함)를 매핑할 수 있습니다. 이 매핑은 지도 및 미디어 앱에 더 높은 디스크 I/O 초과 사용 임곗값을 제공하기 위해 진행됩니다. 이러한 앱이 다른 앱 유형보다 더 많은 데이터를 다운로드하고 디스크에 쓰는 경향이 있기 때문입니다.
  • Component level thresholds. 모든 공급업체 패키지의 일반 임곗값을 정의합니다(즉, Package specific thresholds 또는 Application category specific thresholds에 적용되지 않는 패키지가 이러한 임곗값을 가져옴). 디스크 I/O 초과 사용 구성을 정의할 때 공급업체는 구성요소 수준 임곗값을 0이 아닌 값으로 정의해야 합니다.
  • Package specific thresholds. 공급업체는 특정 공급업체 패키지에 관한 특별 임곗값을 정의할 수 있습니다. 매핑에는 전체 패키지 이름이 포함되어야 합니다. 특정 패키지에서 이 구성에 정의된 임곗값이 다른 구성에 정의된 임곗값보다 우선합니다.
  • Application category specific thresholds. 공급업체는 특정 앱 카테고리의 특별한 임곗값을 지정할 수 있습니다. 앱 카테고리는 지도 및 미디어 앱과 같은 지원되는 카테고리 중 하나여야 합니다. 그 구성에 정의된 임곗값은 Application category mappings를 통해 특정 패키지에 매핑됩니다.
  • System-wide thresholds. 공급업체는 이 구성을 지정하면 안 됩니다.

Vendor package prefixes, Safe-to-terminate packages, Component level thresholds, Package specific thresholds 구성은 공급업체 앱 및 서비스의 공급업체 구성에 의해서만 업데이트 가능합니다. Application category specific thresholds 구성은 모든 지도 및 미디어 앱의 공급업체 구성에 의해서만 업데이트 가능합니다.

초과 사용 임곗값에는 다음 중에 허용된 쓰기 바이트 수가 포함되어 있습니다.

  • 앱/서비스 포그라운드 모드 대 백그라운드 모드
  • 시스템 차고 모드

이러한 분류를 통해 사용자 대상 포그라운드 앱/서비스는 백그라운드 앱/서비스보다 더 많은 데이터를 작성할 수 있습니다. 차고 모드에서는 앱과 서비스가 업데이트를 다운로드하는 경향이 있으므로, 이들은 각각 다른 모드에서 실행되는 앱과 서비스보다 더 높은 임곗값이 필요합니다.

시스템 구성 및 서드 파티 구성

OEM은 시스템 구성 및 서드 파티 구성을 업데이트해서는 안 됩니다.

  • 시스템 구성은 시스템 앱 및 서비스의 I/O 초과 사용 임곗값과 조치를 정의합니다.
    • 이 구성은 Application category mappings를 업데이트할 수도 있습니다. 따라서 이 구성 필드는 시스템 구성과 공급업체 구성 간에 공유됩니다.
  • 서드 파티 구성은 모든 서드 파티 앱의 임곗값을 정의합니다. 시스템에 사전 설치되지 않은 모든 앱은 서드 파티 앱입니다.
    • 공급업체 구성에 의해 정의된 임곗값을 갖는 지도 및 미디어 앱을 제외하고 모든 서드 파티 앱은 동일한 임곗값을 수신합니다(예: 서드 파티 앱은 특별한 임곗값을 수신하지 않음).
    • 아래 디스크 I/O 초과 사용 임곗값은 서드 파티 앱의 기본 임곗값입니다. 이러한 임곗값은 시스템 이미지와 함께 제공됩니다.
      • 앱 포그라운드 모드에서 3GiB 쓰기
      • 앱 백그라운드 모드에서 2GiB 쓰기
      • 시스템 차고 모드에서 4GiB 쓰기
    • 이 수치는 기본 임곗값입니다. 디스크 I/O 사용량을 더 잘 이해하게 되면 이러한 임곗값은 업데이트됩니다.

초과 사용 구성 XML 형식

기본 공급업체 구성은 빌드 이미지의 /vendor/etc/automotive/watchdog/resource_overuse_configuration.xml 위치에 배치할 수 있습니다(선택사항). 이 구성이 지정되지 않으면 시스템 정의 구성이 공급업체 앱과 서비스에도 적용됩니다.

XML 파일에는 구성 필드당 하나의 태그만 포함되어야 합니다. XML 파일에 I/O 초과 사용 구성을 정의해야 합니다. 모든 임곗값은 MiB 단위로 지정해야 합니다.

샘플 XML 구성은 다음과 같이 제공됩니다.

<resourceOveruseConfiguration version="1.0">
     
<componentType> VENDOR </componentType>

     
<!-- List of safe to kill vendor packages. -->
     
<safeToKillPackages>
           
<package> com.vendor.package.A </package>
           
<package> com.vendor.package.B </package>
     
</safeToKillPackages>

     
<!-- List of vendor package prefixes. -->
     
<vendorPackagePrefixes>
           
<packagePrefix> com.vendor.package </packagePrefix>
     
</vendorPackagePrefixes>

     
<!-- List of unique package names to app category mappings. -->
     
<packagesToAppCategoryTypes>
           
<packageAppCategory type="MEDIA"> com.vendor.package.A </packageAppCategory>
           
<packageAppCategory type="MAPS"> com.google.package.B </packageAppCategory>
           
<packageAppCategory type="MEDIA"> com.third.party.package.C </packageAppCategory>
     
</packagesToAppCategoryTypes>

     
<ioOveruseConfiguration>
       
<!-- Thresholds in MiB for all vendor packages that don't have package specific thresholds. -->
           
<componentLevelThresholds>
                 
<state id="foreground_mode"> 1024 </state>
                 
<state id="background_mode"> 512 </state>
                 
<state id="garage_mode"> 3072 </state>
           
</componentLevelThresholds>

           
<packageSpecificThresholds>
                 
<!-- IDs must be unique -->
                 
<perStateThreshold id="com.vendor.package.C">
                   
<state id="foreground_mode"> 400 </state>
                   
<state id="background_mode"> 100 </state>
                   
<state id="garage_mode"> 200 </state>
                 
</perStateThreshold>

                 
<perStateThreshold id="com.vendor.package.D">
                   
<state id="foreground_mode"> 1024 </state>
                   
<state id="background_mode"> 500 </state>
                   
<state id="garage_mode"> 2048 </state>
                 
</perStateThreshold>
           
</packageSpecificThresholds>

           
<!-- Application category specific thresholds. -->
           
<appCategorySpecificThresholds>
                 
<!-- One entry per supported application category -->
                 
<perStateThreshold id="MEDIA">
                   
<state id="foreground_mode"> 600 </state>
                   
<state id="background_mode"> 700 </state>
                   
<state id="garage_mode"> 1024 </state>
                 
</perStateThreshold>

                 
<perStateThreshold id="MAPS">
                   
<state id="foreground_mode"> 800 </state>
                   
<state id="background_mode"> 900 </state>
                   
<state id="garage_mode"> 2048 </state>
                 
</perStateThreshold>
           
</appCategorySpecificThresholds>
     
</ioOveruseConfiguration>
</resourceOveruseConfiguration>

CarWatchdogManager 시스템 API를 통해 초과 사용 구성 업데이트

위의 XML 구성은 빌드 이미지에서만 제공할 수 있습니다. OEM이 빌드가 출시된 후 기기 내 구성을 업데이트하도록 선택한 경우 다음 API를 사용하여 기기 내 구성을 변경할 수 있습니다.

  • 호출자에게 Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG 권한을 부여합니다.
  • 새 구성을 업데이트하고 설정하려면 기존 구성을 사용해야 합니다. API CarWatchdogManager.getResourceOveruseConfigurations를 사용하여 기존 구성을 가져옵니다. 기존 구성을 사용하지 않으면 시스템 구성 및 서드 파티 구성을 포함한 모든 구성을 덮어쓰게 됩니다. 이는 권장되지 않습니다.
  • 델타 변경사항을 사용하여 기존 구성을 업데이트하고 새 구성을 설정합니다. 시스템 구성요소 구성 및 서드 파티 구성요소 구성을 업데이트하지 마세요.
  • API CarWatchdogManager.setResourceOveruseConfigurations를 사용하여 새 구성을 설정합니다.
  • 디스크 I/O 초과 사용 구성을 가져오고 설정하려면 플래그 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO를 사용합니다.

다음은 리소스 초과 사용 구성을 업데이트하는 샘플 구현입니다.

void updateResourceOveruseConfigurations() {
   
CarWatchdogManager manager =
       
(CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE);

   
List<ResourceOveruseConfiguration> resourceOveruseConfigurations =
        manager
.getResourceOveruseConfigurations(
           
CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO);

   
List<ResourceOveruseConfiguration> newResourceOveruseConfigurations =
           
new List<>();
   
ResourceOveruseConfiguration vendorConfiguration;
   
for(ResourceOveruseConfiguration config : resourceOveruseConfigurations) {
       
// Do not update the configurations of the system and third-party component types.
       
if (config.getComponentType()
           
!= ResourceOveruseConfiguration.COMPONENT_TYPE_VENDOR) {
            newResourceOveruseConfigurations
.add(config);
           
continue;
       
}
        vendorConfiguration
= config;
   
}

   
if (vendorConfiguration == null) {
       
ResourceOveruseConfiguration.Builder vendorConfigBuilder =
           
new ResourceOveruseConfiguration.Builder();
        initializeConfig
(vendorConfigBuilder);
        newResourceOveruseConfigurations
.add(vendorConfigBuilder.build());
   
} else {
       
ResourceOveruseConfiguration newVendorConfig =
            updateConfig
(vendorConfiguration);
        newResourceOveruseConfigurations
.add(newVendorConfig);
   
}
   
int result = manager.setResourceOveruseConfigurations(
        newResourceOveruseConfigurations
,

   
if (result != CarWatchdogManager.RETURN_CODE_SUCCESS) {
       
// Failed to set the resource overuse configurations.
   
}
}

/** Sets the delta between the old configuration and the new configuration. */
ResourceOveruseConfiguration updateConfig(
   
ResourceOveruseConfiguration oldConfiguration) {
   
// Replace com.vendor.package.A with com.vendor.package.B in the safe-to-kill list.
   
List<String> safeToKillPackages = oldConfiguration.getSafeToKillPackages();
    safeToKillPackages
.remove("com.vendor.package.A");
    safeToKillPackages
.add("com.vendor.package.B");

   
ResourceOveruseConfiguration.Builder configBuilder =
       
new ResourceOveruseConfiguration.Builder(
            oldConfiguration
.getComponentType(),
            safeToKillPackages
,
            oldConfiguration
.getVendorPackagePrefixes(),
            oldConfiguration
.getPackagesToAppCategoryTypes());

    configBuilder
.addVendorPackagePrefixes("com.vendor.");
    configBuilder
.addPackagesToAppCategoryTypes("com.vendor.package.B",
       
ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS);

   
IoOveruseConfiguration oldIoConfiguration = oldConfiguration.getIoOveruseConfiguration();
   
IoOveruseConfiguration.Builder ioConfigBuilder =
       
new IoOveruseConfiguration.Builder(
            oldIoConfiguration
.getComponentLevelThresholds(),
            oldIoConfiguration
.getPackageSpecificThresholds(),
            oldIoConfiguration
.getAppCategorySpecificThresholds(),
            oldIoConfiguration
.getSystemWideThresholds());

   
// Define the amount of bytes based on the flash memory specification, expected lifetime,
   
// and estimated average amount of bytes written by a package during different modes.
    ioConfigBuilder
.addPackageSpecificThresholds("com.vendor.package.B",
       
new PerStateBytes(/* foregroundModeBytes= */ 2 * 1024 * 1024 * 1024,
                         
/* backgroundModeBytes= */ 500 * 1024 * 1024,
                         
/* garageModeBytes= */ 3 * 1024 * 1024 * 1024));


   
return configBuilder.setIoOveruseConfiguration(ioConfigBuilder.build()).build();
}

리소스 초과 사용을 모니터링하는 앱

공급업체 앱 및 서드 파티 앱은 워치독에서 앱별 리소스 초과 사용 알림을 수신 대기하거나, 최대 지난 30일 동안의 앱별 리소스 초과 사용 통계를 가져오기 위해 CarWatchdogManager를 폴링할 수 있습니다.

리소스 초과 사용 알림 수신 대기

앱은 디스크 I/O 초과 사용 임곗값의 80% 또는 100%를 초과할 경우 앱별 알림을 수신하기 위해 리소스 초과 사용 리스너를 구현하고 CarWatchdogManager와 함께 리스너를 등록할 수 있습니다. 앱은 이러한 알림을 사용하여 다음 작업을 할 수 있습니다.

  • 오프라인 분석을 위해 디스크 I/O 초과 사용 통계를 기록합니다. 앱 개발자는 이 로깅을 사용하여 디스크 I/O 초과 사용 문제를 디버그할 수 있습니다.
  • 초과 사용 카운터가 초기화될 때까지 디스크 I/O 쓰기를 줄입니다.

자바 클라이언트

  1. CarWatchdogManager.ResourceOveruseListener를 상속하여 리스너를 구현합니다.
    class ResourceOveruseListenerImpl implements
         
    CarWatchdogManager.ResourceOveruseListener {
               
    @Override
               
    public void onOveruse(
                     
    @NonNull ResourceOveruseStats resourceOveruseStats) {
                     
    // 1. Log/Upload resource overuse metrics.
                     
    // 2. Reduce writes until the counters reset.

                     
    IoOveruseStats ioOveruseStats = resourceOveruseStats.getIoOveruseStats();
                     
    // Stats period - [ioOveruseStats.getStartTime(), ioOveruseStats.getStartTime()
                     
    //   + ioOveruseStats.getDurationInSeconds()]
                     
    // Total I/O overuses - ioOveruseStats.getTotalOveruses()
                     
    // Total bytes written - ioOveruseStats.getTotalBytesWritten()
                     
    // Remaining write bytes for the current UTC calendar day -
                     
    //    ioOveruseStats.getRemainingWriteBytes()
               
    }
         
    }
    }
  2. CarWatchdogManager.addResourceOveruseListener를 호출하여 리스너 인스턴스를 등록합니다.
    private void addResourceOveruseListener() {
         
    CarWatchdogManager manager =
               
    (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE);
         
    // Choose a proper executor to handle resource overuse notifications.
         
    Executor executor = mContext.getMainExecutor();
          manager
    .addResourceOveruseListener(
                executor
    , CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
                mListenerImpl
    );
    }
  3. 앱의 수신 대기가 끝나면 리스너 인스턴스의 등록을 취소합니다.
    private void removeResourceOveruseListener() {
       
    CarWatchdogManager manager =
               
    (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE);
        mCarWatchdogManager
    .removeResourceOveruseListener(
              mListenerImpl
    );
    }

네이티브 클라이언트

  1. 빌드 규칙의 shared_libs 종속 항목에 carwatchdog_aidl_interface-ndk_platform을 포함합니다.

    Android.bp

    cc_binary {
        name
    : "sample_native_client",
        srcs
    : [
           
    "src/*.cpp"
       
    ],
        shared_libs
    : [
           
    "carwatchdog_aidl_interface-ndk_platform",
           
    "libbinder_ndk",
       
    ],
        vendor
    : true,
    }
  2. 공급업체 서비스 도메인에 바인더(binder_user 매크로)를 사용하도록 허용하고 공급업체 서비스 도메인을 carwatchdog 클라이언트 도메인((carwatchdog_client_domain macro) 매크로)에 추가하려면 SELinux 정책을 추가합니다. sample_client.tefile_contexts의 경우 아래 코드를 참고하세요.

    sample_client.te

    type sample_client, domain;
    type sample_client_exec
    , exec_type, file_type, vendor_file_type;

    carwatchdog_client_domain
    (sample_client)

    init_daemon_domain
    (sample_client)
    binder_use
    (sample_client)

    file_contexts

    /vendor/bin/sample_native_client  u:object_r:sample_client_exec:s0
  3. BnResourceOveruseListener를 상속하여 리소스 초과 사용 리스너를 구현합니다. 리소스 초과 사용 알림을 처리하도록 BnResourceOveruseListener::onOveruse를 재정의합니다.

    ResourceOveruseListenerImpl.h

    class ResourceOveruseListenerImpl : public BnResourceOveruseListener {
    public:
        ndk
    ::ScopedAStatus onOveruse(
           
    ResourceOveruseStats resourceOveruseStats) override;

    private:
       
    void initialize();
       
    void terminate();

        std
    ::shared_ptr<ICarWatchdog> mWatchdogServer;
        std
    ::shared_ptr<IResourceOveruseListener> mListener;
    }

    ResourceOveruseListenerImpl.cpp

    ndk::ScopedAStatus ResourceOveruseListenerImpl::onOveruse(
         
    ResourceOveruseStats resourceOveruseStats) {

         
    // 1. Log/Upload resource overuse metrics.
         
    // 2. Reduce writes until the counters reset.

         
    if (stats.getTag() != ResourceOveruseStats::ioOveruseStats) {
               
    // Received resourceOveruseStats doesn't contain I/O overuse stats.
         
    }

         
    const IoOveruseStats& ioOveruseStats = stats.get();
         
    // Stats period - [ioOveruseStats.startTime,
         
    //   ioOveruseStats.startTime + ioOveruseStats.durationInSeconds]
         
    // Total I/O overuses - ioOveruseStats.totalOveruses
         
    // Total bytes written - ioOveruseStats.writtenBytes
         
    // Remaining write bytes for the current UTC calendar day -
         
    //    ioOveruseStats.remainingWriteBytes

         
    return ndk::ScopedAStatus::ok();
    }
  4. 바인더 스레드 풀을 시작하고 리소스 초과 사용 리스너를 워치독 서버에 등록합니다. 워치독 서버가 서비스 이름 android.automotive.watchdog.ICarWatchdog/default에 등록되어 있습니다.

    main.cpp

    int main(int argc, char** argv) {
       
    ABinderProcess_setThreadPoolMaxThreadCount(1);
       
    ABinderProcess_startThreadPool();
        std
    ::shared_ptr<ResourceOveruseListenerImpl> listener =
            ndk
    ::SharedRefBase::make<ResourceOveruseListenerImpl>();

       
    // The listener is added in initialize().
        listener
    ->initialize();

       
    ... Run service ...

       
    // The listener is removed in terminate().
        listener
    ->terminate();
    }

    ResourceOveruseListenerImpl.cpp

    void ResourceOveruseListener::initialize() {
        ndk
    ::SpAIBinder binder(AServiceManager_getService(
               
    "android.automotive.watchdog.ICarWatchdog/default"));
        std
    ::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder);
        mWatchdogServer
    = server;

        std
    ::shared_ptr<IResourceOveruseListener> listener =
           
    IResourceOveruseListener::fromBinder(this->asBinder());
        mWatchdogServer
    ->addResourceOveruseListener(
          std
    ::vector<int>{ResourceType.IO}, listener);
        mListener
    = listener;
    }

    void ResourceOveruseListener::terminate() {
        mWatchdogServer
    ->removeResourceOveruseListener(mListener);
    }

리소스 초과 사용 통계 폴링

앱은 최근 30일의 앱별 I/O 초과 사용 통계 ATS를 가져오기 위해 CarWatchdogManager를 폴링할 수 있습니다.

Java 클라이언트

CarWatchdogManager.getResourceOveruseStats를 사용하여 리소스 초과 사용 통계를 가져옵니다. CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO 플래그를 전달하여 디스크 I/O 초과 사용 통계를 가져옵니다.

private void getResourceOveruseStats() {
     
CarWatchdogManager manager =
           
(CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE);

     
// Returns resource overuse stats with I/O overuse stats for the past
     
// 7 days. Stats are available for up to the past 30 days.
     
ResourceOveruseStats resourceOveruseStats =
            mCarWatchdogManager
.getResourceOveruseStats(
                 
CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO,
                 
CarWatchdogManager.STATS_PERIOD_PAST_7_DAYS);

     
IoOveruseStats ioOveruseStats = resourceOveruseStats.getIoOveruseStats();
     
// Stats period - [ioOveruseStats.getStartTime(), ioOveruseStats.getStartTime()
     
//   + ioOveruseStats.getDurationInSeconds()]
     
// Total I/O overuses - ioOveruseStats.getTotalOveruses()
     
// Total bytes written - ioOveruseStats.getTotalBytesWritten()
     
// Remaining write bytes for the UTC calendar day -
     
//    ioOveruseStats.getRemainingWriteBytes()
}

네이티브 클라이언트

CarWatchdogServer.getResourceOveruseStats를 사용하여 리소스 초과 사용 통계를 가져옵니다. ResourceType.IO enum을 전달하여 디스크 I/O 초과 사용 통계를 가져옵니다.

void getResourceOveruseStats() {
      ndk
::SpAIBinder binder(AServiceManager_getService(
           
"android.automotive.watchdog.ICarWatchdog/default"));
      std
::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder);
     
// Returns the stats only for the current UTC calendar day.
     
const std::vector<ResourceOveruseStats> resourceOveruseStats;
      ndk
::ScopedAStatus status = server.getResourceOveruseStats(
            std
::vector<int>{ResourceType.IO}, &resourceOveruseStats);
     
if (!status.isOk()) {
           
// Failed to get the resource overuse stats.
           
return;
     
}

     
for (const auto& stats : resourceOveruseStats) {
           
if (stats.getTag() != ResourceOveruseStats::ioOveruseStats) {
                 
continue;
           
}
           
const IoOveruseStats& ioOveruseStats = stats.get();
           
// Stats period - [ioOveruseStats.startTime,
           
//   ioOveruseStats.startTime + ioOveruseStats.durationInSeconds]
           
// Total I/O overuses - ioOveruseStats.totalOveruses
           
// Total bytes written - ioOveruseStats.writtenBytes
           
// Remaining write bytes for the current UTC calendar day -
           
//   ioOveruseStats.remainingWriteBytes
     
}
}

리소스 초과 사용 UX

앱 성능 설정의 우선순위 지정

앱 설정 페이지에는 Prioritize app performance 설정이 있습니다(아래 이미지 참고). 이는 사용자가 시스템 성능 및 장기 하드웨어 성능보다 앱 성능을 우선시할 수 있는 설정입니다. 이 설정은 리소스 초과 사용 시 안전하게 종료되는 앱에만 사용할 수 있습니다. 그 외의 경우에는 이 설정은 비활성화됩니다. 앱에서 이 설정이 사용 중지(기본 설정)되면 앱은 리소스 초과 사용 시 종료될 수 있습니다. 그 외의 경우에는 앱이 리소스 초과 사용 시 종료되지 않습니다.

사용자가 이 설정을 켜면 다음 확인 대화상자에 설정을 켜면 어떻게 되는지 설명이 표시됩니다.

90일이 지나면 이 설정은 기본값으로 자동 재설정됩니다. 날짜 제한은 watchdogUserPackageSettingsResetDays를 사용하여 RRO 오버레이 앱으로 수정할 수 있으며 최대 180일까지입니다. 자세한 내용은 런타임 시 앱 리소스 값 변경을 참고하세요. 다음 오버레이 태그 예는 AndroidManifest.xml에 포함될 수 있습니다.

<overlay android:priority="<insert-value>"
       android:targetPackage="com.android.car.updatable"
       android:targetName="CarServiceCustomization"
       android:resourcesMap="@xml/overlays" />

res/values/config.xml에서:

<resources>
 
<integer name="watchdogUserPackageSettingsResetDays">value</integer>
</resources>

res/xml/overlays.xml에서:

<overlay>
 
<item target="integer/watchdogUserPackageSettingsResetDays" value="@integer/watchdogUserPackageSettingsResetDays" />
</overlay>

사용자 알림

앱 또는 서비스가 특정 기간 내에 디스크 I/O를 반복적으로 초과 사용(예: 정의된 임곗값을 초과할 정도로 데이터를 디스크에 씀)하고 리소스 초과 사용 시 안전하게 종료된 경우 사용자에게 차량이 운전자 주의 분산 행동 허용 상태로 전환되었음을 알립니다.

운전 중에 첫 번째 사용자 알림은 운전자 알림으로 게시되고 그 외 다른 알림은 알림 센터에 게시됩니다.

예를 들어 앱이 디스크 I/O를 반복적으로 초과 사용할 경우 사용자는 다음과 같은 알림을 받습니다.

  • 사용자가 앱 우선순위 지정 버튼을 클릭하면 앱의 설정 페이지가 실행됩니다. 여기에서 사용자는 앱 성능 우선순위 지정 설정을 켜거나 끌 수 있습니다.
  • 사용자가 앱 사용 중지 버튼을 클릭하면 사용자가 앱을 실행하거나 앱의 설정 페이지에서 앱을 사용 설정할 때까지 앱이 사용 중지됩니다.
  • 제거 가능한 앱의 경우 앱 사용 중지 버튼은 앱 제거 버튼으로 대체됩니다. 사용자가 앱 제거 버튼을 클릭하면 앱의 설정 페이지가 실행되고 사용자는 그 페이지에서 앱을 제거할 수 있습니다.

런처 구현 권장사항

리소스 초과 사용으로 인해 앱이 사용 중지되면 앱은 기본 런처 앱에 표시되지 않습니다. CarService가 앱의 enabled 상태를 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED로 업데이트하기 때문입니다. OEM은 내장된 런처 구현을 업데이트하여 이러한 앱을 이례적인 것으로 표시해야 합니다. 그래야 사용자가 필요할 때 이러한 앱을 사용할 수 있습니다. 빌드 출시에 따라 다음 권장사항을 참고하세요.

Android SC V2 출시