Чрезмерное пробуждение Alarm Manager в android с помощью Служб Google Play Services

Я получил отчет от Android Vital на Google Play Console о пробуждениях с избыточным аварийным сигналом:

https://developer.android.com/topic/performance/vitals/wakeup.html

Я использую API местоположения из Служб Google Play для запроса обновлений местоположения в фоновом режиме. В отчете показано, что чрезмерные пробуждения вызваны com.google.android.location.ALARM_WAKEUP_LOCATOR из LocationListener.

Ниже фрагмента кода, который вызывает аварийные сигналы:

private synchronized void buildGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(context)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
    mGoogleApiClient.connect();
}

/**
 * Runs when a GoogleApiClient object successfully connects.
 */
@Override
public void onConnected(Bundle connectionHint) {
    try {
        // Set location request
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(5 * 60000);
        mLocationRequest.setFastestInterval(60000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        mLocationRequest.setMaxWaitTime(30 * 60000);

        // Create a pending intent to listening on location service when the update become available
        Intent mIntent = new Intent(context, LocationReceiver.class);
        mIntent.setAction(LocationReceiver.LOCATION_EXTRA);
        mPendingIntent = PendingIntent.getBroadcast(context, 42, mIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        // Permission check before launching location services
        if (ContextCompat.checkSelfPermission(context,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Связана ли эта тревога с API-интерфейсом местоположения от сервисов Google Play?

Кто-нибудь знает, как исправить эту проблему?

Ответ 1

Местоположение Google api

Это проблема с com.google.android.location.ALARM_WAKEUP_LOCATOR просыпанием устройств каждые 60 секунд и сдерживанием их в течение 15 секунд, вызывая большую батарею проблемы дренажа.

Там были исправления для использования телефона через внешние приложения и обучение пользователей тому, как фактически аннулировать разрешение для приложения.

Решение

Ниже приведены инструменты для уменьшения использования батареи в приложении.

Невозможно предоставить настраиваемое решение для приложения, так как решение зависит от варианта использования и бизнес-логики приложения и анализа затрат и выгод от того, что вы хотите достичь с обновлением местоположения.

Временные интервалы

Не удивительно, что проблемы с производительностью батареи. Из следующих настроек:

mLocationRequest.setInterval(5 * 60000);
mLocationRequest.setFastestInterval(60000);
mLocationRequest.setMaxWaitTime(30 * 60000);

Ваш интервал устанавливается на обновление каждые 5 минут (5 * 60000 мс). Это 24 часа в сутки. Если это обновление успешно каждые 5 минут: 12 раз/час == 288 раз в день.

Самый быстрый интервал устанавливается в 1 минуту (60000). Хотя это доступно, поскольку доступ к местоположению осуществляется в другом месте устройства, он все равно будет использовать питание в вашем приложении).

Максимальное время составляет всего 30 минут. Это означает, что в лучшем случае устройство будет разбужено и опрошено не менее 48 раз в день.

Увеличить это время.

setMaxWaitTime... Это может потреблять меньше батареи и давать более точные местоположения, в зависимости от аппаратных возможностей устройства. Вы должны установить это ценность должна быть максимально возможной для ваших нужд, если вам не нужна немедленная доставка....

В Android 8 Google ограничивает количество запросов только несколько часов в час. Подумайте об использовании этого в качестве ориентира в задании интервалов для запросов.

Ограничение количества обновлений

Количество обновлений в течение определенного периода времени может быть ограничено. Активно отменяя запрос местоположения после того, как количество обновлений было использовано, или установив expiration в запросе. Таким образом, приложение может управлять, создавая запрос на какой-то триггер в приложении и тщательно управляемый, чтобы он не продолжался бесконечно. Трудно создать поток, так как я не знаю пример использования для приложения.

setNumUpdates (int numUpdates)

По умолчанию местоположения постоянно обновляются до тех пор, пока запрос не будет явно удалены, однако вы можете запросить заданное число Обновления. Например, если вашему приложению требуется только один свежий местоположения, затем вызовите этот метод со значением 1 перед передачей запрос клиенту местоположения.

Остановить обновление местоположения

Другим вариантом является управление остановкой обновлений местоположений, когда они не требуются. Ссылки приводят примеры вызова этого, когда действие теряет фокус, однако оно может быть реализовано в приложении, когда выполняются определенные требования (что в вашей бизнес-логике) или даже путем предоставления пользователю возможности включать и выключать его из приложения сам.

Оптимизация аккумулятора

Убедитесь, что ваше приложение не игнорирует оптимизацию аккумулятора.

Смещение

Также управление setSmallestDisplacement (float smallestDisplacementMeters) поможет точно настроить приложение в зависимости от бизнес-логики.

перед обновленным вопросом было написано следующее.

Как часто обновления приложений могут устанавливаться как разработчиком, так и пользователем. интервалы и приоритеты.

Для developer.

Вы можете установить их при создании запроса на местоположение, например:

protected void createLocationRequest() {
    LocationRequest mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(10000);
    mLocationRequest.setFastestInterval(5000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
}

Существует также параметр PRIORITY_NO_POWER, что означает, что приложение будет получать обновления только тогда, когда пользователь запрашивает их.

Для пользователя.

Вам понадобится Запрос пользователю изменить настройки местоположения

task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
    @Override
    public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
        // All location settings are satisfied. The client can initialize
        // location requests here.
        // ...
    }
});

task.addOnFailureListener(this, new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        int statusCode = ((ApiException) e).getStatusCode();
        switch (statusCode) {
            case CommonStatusCodes.RESOLUTION_REQUIRED:
                // Location settings are not satisfied, but this can be fixed
                // by showing the user a dialog.
                try {
                    // Show the dialog by calling startResolutionForResult(),
                    // and check the result in onActivityResult().
                    ResolvableApiException resolvable = (ResolvableApiException) e;
                    resolvable.startResolutionForResult(MainActivity.this,
                            REQUEST_CHECK_SETTINGS);
                } catch (IntentSender.SendIntentException sendEx) {
                    // Ignore the error.
                }
                break;
            case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                // Location settings are not satisfied. However, we have no way
                // to fix the settings so we won't show the dialog.
                break;
        }
    }
});

В управлять изменениями в настройках пользователя используйте обратный вызов местоположения.

... вы можете использовать новый класс LocationCallback вместо существующих LocationListener для получения LocationAvailability обновлений к обновлениям местоположений, что дает вам простой обратный вызов, когда настройки может измениться, что повлияет на текущий набор LocationRequests.

Google обратился к этой проблеме в Android 8.

В целях снижения энергопотребления Android 8.0 (уровень API 26) как часто фоновые приложения могут извлекать текущий ток место нахождения. Приложения могут получать обновления местоположения всего несколько раз каждый час.

Примечание. Эти ограничения распространяются на все приложения, используемые на запущенных устройствах   Android 8.0 (уровень API 26) или выше, независимо от цели приложения   Версия SDK.


Если вы используете диспетчер аварийных сигналов.

Это может быть связано с Alarm Manager.

Это не простое исправление, в конечном итоге вам потребуется переписать, как вы планируете свои обновления.

  • Чтобы по крайней мере замедлить проблему, вам потребуется отладить код и найти любые экземпляры, в которых диспетчер аварийных сигналов вызывает или создает расписания и сокращает интервалы.

  • После этого вам нужно будет переписать всю планировщику обновления местоположения для всего приложения.

Исправить проблему

Определите места в своем приложении, где вы планируете будильники будильника и уменьшить частоту срабатывания этих аварийных сигналов. Вот некоторые советы:

  • Ищите вызовы для различных set() методов в AlarmManager, которые включают флаг RTC_WAKEUP или ELAPSED_REALTIME_WAKEUP.
  • Мы рекомендуем включить имя вашего пакета, класса или метода в имени тега будильника, чтобы вы могли легко определить местоположение в своем источник, в котором установлен будильник. Вот несколько дополнительных советов:
    • Оставьте личную идентификационную информацию (PII) в названии, например, адрес электронной почты. В противном случае журнал устройств _UNKNOWN вместо имени тревоги.
    • Не вводите имя класса или метода программно, например, вызывая getName(), потому что он может быть запутан Proguard. Вместо этого используйте стробированную строку.
    • Не добавляйте счетчик или уникальные идентификаторы в теги предупреждений. Система не сможет агрегировать аварийные сигналы, установленные таким образом потому что все они имеют уникальные идентификаторы.

После устранения проблемы убедитесь, что ваши будильники активированы как ожидалось, выполнив следующую команду ADB:

Аварийный сигнал dumpys оболочки adb

Эта команда предоставляет информацию о состоянии системы сигнализации обслуживание на устройстве. Для получения дополнительной информации см. dumpsys.

Если у вас есть особые проблемы с любым из вышеперечисленных вопросов, вам нужно отправить другой вопрос с помощью mcve.

Чтобы улучшить приложение, потребуется переписать код, упомянутый здесь, в Best Practices. Не используйте диспетчер аварийных сигналов для планирования фоновых задач, и местоположение будет считаться фоновой задачей, если телефон спит. Плюс вы говорите, что это фоновая задача. Используйте JobScheduler или Firebase JobDispatcher.

Если диспетчер аварийных сигналов является лучшим выбором (которого он не здесь), важно иметь хороший текст здесь Планирование повторных сигналов тревоги, но вы необходимо Понять компромиссы

Слабо спроектированный сигнал тревоги может привести к утечке аккумулятора и значительно увеличить нагрузку на серверы.