Настройки оптимизации Proguard: включение слияния классов, трансляции и поля /* в современных API и версиях Proguard

Я долгое время запутывал свои приложения, со следующими настройками, которые я принимал как мантры, потому что они были рекомендациями Google

-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*

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

Итак, мне интересно, нужны ли отключенные настройки оптимизации...

  • на сегодняшний день Android SDK и последние версии Proguard, я только нацеливаю устройства с Android 4.0.3 и выше (15) и пользуюсь Proguard 5.1.
  • и для приложений, которые не занимаются экзотическими материалами, и имеют надлежащим образом написанные proguard.cfg инструкции по сохранению соответствующих проблемных классов и т.д.

Большинство ответов, приведенных в этом выпуске, имеют противоречивую информацию и относятся к довольно старым версиям API.

Один за другим:

! Код/упрощение/арифметика

Я нашел обсуждение Группы Google, где они говорят, что simplification/arithmethic не требуется для SDK после Android Donut. Я предполагаю тогда, я могу безопасно включить эту оптимизацию.

класс!/Присоединяемых/*

Похоже, proguard делает хорошую работу в моих проектах с включенной оптимизацией:

[proguard]   Number of vertically merged classes:         296
[proguard]   Number of horizontally merged classes:       445

Существуют ли другие побочные эффекты, кроме следов стека? Я имею в виду, что побочные эффекты, связанные с сбоем приложения, а не отладки проблем. Я нашел этот связанный вопрос, но он не уверен, что это безопасно или нет.

! field/* и! code/simplification/cast

Я прочитал в этом вопросе, на который ответил автор ProGuard, что они были включены, чтобы избежать ошибок со старыми версиями Proguard. Так безопасно ли их активировать на Proguard 5.1?

Ответ 1

Общие рекомендации: нет гарантии, что оптимизация не будет работать, но всегда есть риск. То, что делают настройки Android proguard по умолчанию, - это обеспечить конфигурацию, которая минимизирует этот риск, поэтому почему они выглядят настолько консервативными для вашей конкретной ситуации.

Включение этих оптимизаций просто означает, что если что-то сработает, вы не можете быть так же уверенны в корневой причине. В общем, шаг proguard имеет менее серьезные гарантии того, какие результаты должны быть относительно входных данных, что является источником недетерминизма в вашей программе. Небольшие изменения в коде могут привести к значительному изменению поведения во время выполнения, и это невозможно узнать, пока вы фактически не запустите программу, в зависимости от вашей конфигурации.

В общем, если вы можете запустить APK, и все это работает - тогда отлично, оптимизация работает для вас. Но они не гарантированы.

Ответ 2

Так безопасно ли их активировать на Proguard [5.1]?

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

Мы используем ProGuard 5.2.1, и мы сталкиваемся с ошибкой при обновлении оптимизации field/* (точнее, field/removal/writeonly, похоже, вызывает проблему). В нашем коде используется protobuf и включение этой оптимизации приводит к сбою ProGuard с этим сообщением на третьем проходе оптимизации:

Optimizing...
 Unexpected error while evaluating instruction:
  Class       = [com/google/protobuf/FieldSet$1]
  Method      = [()V]
  Instruction = [308] isub
  Exception   = [java.lang.IllegalArgumentException] (Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue])
Unexpected error while performing partial evaluation:
  Class       = [com/google/protobuf/FieldSet$1]
  Method      = [()V]
  Exception   = [java.lang.IllegalArgumentException] (Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue])
Warning: Exception while processing task java.io.IOException: java.lang.IllegalArgumentException: Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue]

Это означает, что тот факт, что эти оптимизации были отключены на протяжении стольких лет, означает, что они, вероятно, не так хорошо поддерживаются, как другие. К счастью, это было поймано во время компиляции, но повторное включение некоторых из этих оптимизаций (например, горизонтальное объединение классов с помощью class/merging/*) может легко сломать ваше приложение в определенных версиях/сборках Android, не сообщая должным образом вам "разработчику" (например, он может скомпрометировать dexopts или вообще не установить с помощью VerifyError).