Используем AspectJ в Android

Written by elwood

Операционная система Android может делать с вашим приложением много всякого интересного. Например, пересоздавать Activity при повороте экрана, закрывать Activity, переоткрывать их, вызывать onPause(), закрывать вместе с ними диалоги, убивать процессы и так далее. При работе приложения могут происходить звонки, и Activity может быть уничтожена (и даже процесс может быть убит). Возможных кейсов очень много, и сложно предусмотреть всё и сразу. Обычно программист разумный поступает так: согласно документации и набору проведённых вручную тестов выводятся основные правила (rules of thumb), по которым пишется код, далее этот код обильно сдабривается ассертами и сообщениями в лог в ключевых местах, и потом все проблемы можно диагностировать по падениям приложения на ассертах и полученным стектрейсам. После исследования каждой такой проблемы понимание постепенно улучшается, и программист пишет код уже с учётом обнаруженных потенциальных проблем. Однако это работает только для обычных, часто встречающихся ситуаций. Для сложных или редких юзкейсов повторно воспроизвести баг бывает очень сложно, а по стектрейсу и логам не всегда можно понять, что послужило причиной падения. В таких случаях лучше всего помогают сообщения в логах, которые обозначают места вызова функций. Но расставлять их вручную дико неудобно. Для обычного JVM есть известное решение – инструментирование байткода классов после компиляции с помощью таких инструментов, как AspectJ. Эта штука умеет внедрять указанный код перед, после и даже вместо вызова функций, программисту достаточно задать правила, по которым тулза будет определять, какой код надо модифицировать, а какой – нет. Мы просто можем в местах вызова всех методов писать в лог сообщение о том, какой метод был вызван. Загвоздка заключается в том, что байткод виртуальной машины Dalvik (используемой в Android) она, конечно, не понимает. Но мы-то знаем, что приложения под android собираются в 2 этапа, сначала код компилируется в обычные java class-файлы, а потом уже эти классы конвертируются в файл dex! И уже этот dex запаковывается в apk. Так что если у нас получится вклиниться в процесс сборки между этими этапами, то с большой степенью вероятности всё получится, и мы сможем использовать функциональность AspectJ в андроид приложениях. Я нашел пример, который делает ровно то, что мне нужно, единственной проблемой было то, что он не собирался – там был build.xml старого формата, который уже не работал в современных версиях Android SDK. В общем, пришлось делать самому, и результат я выложил в виде тестового приложения.

https://bitbucket.org/igor_kostromin/android-aspectj-demo/