Udało mi się odpowiedzieć na moje pytanie. Na co mogę zrozumieć z kodu źródłowego nie jest możliwe 3 punkty wejścia dla połączeń Java:
- ArtMethod :: Invoke (sztuka/czas pracy/lustro/art_method.cc)
- Execute (sztuka/czas pracy /interpreter/interpreter.cc)
- DoCall (sztuka/czas pracy/tłumacz/interpreter_common.cc)
ArtMethod :: Invoke wydaje się być wykorzystywane do refleksji i wywołanie metody bezpośrednio ze wskaźnikiem do OAT sekcja kodu. (Ponownie, brak dokumentacji, może być niedokładna).
Wykonanie w końcu wywołanie DoCall ogólnie.
Istnieje kilka optymalizacji ART, które utrudniają naukę wywołań Java, takich jak metoda inline i bezpośrednie wywoływanie adresów offsetowych.
Pierwszym krokiem jest wyłączenie tych optymalizacje:
W urządzeniu/markowy/model/device.mk (w moim przypadku urządzenia/LGE/Hammerhead/device.mk dla Nexus 5):
Dodaj opcję "tylko do interpretacji", aby dex2oat. Dzięki tej opcji ART kompiluje tylko ścieżkę klasy rozruchowej, więc aplikacje nie będą kompilowane w OAT.
PRODUCT_PROPERTY_OVERRIDES := \
dalvik.vm.dex2oat-filter=interpret-only
Drugi etap polega na wyłączeniu inline w sztuce/kompilatora/dex/frontend.cc:
Odkomentuj "kSuppressMethodInlining".
/* Default optimizer/debug setting for the compiler. */
static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations
(1 << kLoadStoreElimination) |
// (1 << kLoadHoisting) |
// (1 << kSuppressLoads) |
// (1 << kNullCheckElimination) |
// (1 << kClassInitCheckElimination) |
(1 << kGlobalValueNumbering) |
// (1 << kPromoteRegs) |
// (1 << kTrackLiveTemps) |
// (1 << kSafeOptimizations) |
// (1 << kBBOpt) |
// (1 << kMatch) |
// (1 << kPromoteCompilerTemps) |
// (1 << kSuppressExceptionEdges) |
(1 << kSuppressMethodInlining) |
0;
Ostatnim krokiem jest wyłączenie kodu offsetu bezpośredniego wywołania w sztuce/kompilator/kierowcy/compiler_driver.cc:
-bool use_dex_cache = GetCompilerOptions().GetCompilePic();
+bool use_dex_cache = true;
z tymi zmianami wszystkim różne połączenia spadnie w funkcji DoCall gdzie możemy wreszcie dodaj naszą ukierunkowaną procedurę logowania.
w art/runtime/tłumacz/interpreter_common.h, dodać na początku obejmuje:
#ifdef HAVE_ANDROID_OS
#include "cutils/properties.h"
#endif
w art/runtime/tłumacz/interpreter_common.cc, dodać na początku funkcji DoCall:
#ifdef HAVE_ANDROID_OS
char targetAppVar[92];
property_get("target.app.pid", targetAppVar, "0");
int targetAppPID = atoi(targetAppVar);
if(targetAppPID != 0 && targetAppPID == getpid())
LOG(INFO) << "DoCall - " << PrettyMethod(method, true);
#endif
Do kierowania aplikacji używam właściwości, która ustawia docelowy pid. Do tego potrzebujemy systemu lib/core/libcutils, a ta lib jest dostępna tylko wtedy, gdy AOSP jest skompilowany dla prawdziwego telefonu (bez zmywania z obecnymi plikami Makefile).
Rozwiązanie nie będzie działać na emulatorze. (
Tylko zgadywanie, nigdy nie próbowano
EDYCJA: potwierdzona, "cutils/properties.h" nie mogą być dodane do kompilacji emulatora).
Po skompilowaniu i miganiu załatanego AOSP, uruchom aplikację, ps | grep do znalezienia PID i ustawić właściwość root:
[email protected]:/ # ps | grep contacts
u0_a2 4278 129 1234668 47356 ffffffff 401e8318 S com.android.contacts
[email protected]:/ # setprop target.app.pid 4278
[email protected]:/ # logcat
[...]
I/art (4278): DoCall - int android.view.View.getId()
I/art (4278): DoCall - void com.android.contacts.activities.PeopleActivity$ContactsUnavailableFragmentListener.onCreateNewContactAction()
I/art (4278): DoCall - void android.content.Intent.<init>(java.lang.String, android.net.Uri)
I/art (4278): DoCall - void android.app.Activity.startActivity(android.content.Intent)
I/ActivityManager( 498): START u0 {act=android.intent.action.INSERT dat=content://com.android.contacts/contacts cmp=com.android.contacts/.activities.ContactEditorActivity} from uid 10002 on display 0
V/WindowManager( 498): addAppToken: AppWindowToken{3a82282b token=Token{dc3f87a ActivityRecord{c0aaca5 u0 com.android.contacts/.activities.ContactEditorActivity t4}}} to stack=1 task=4 at 1
I/art (4278): DoCall - void android.app.Fragment.onPause()
I/art (4278): DoCall - void com.android.contacts.common.list.ContactEntryListFragment.removePendingDirectorySearchRequests()
I/art (4278): DoCall - void android.os.Handler.removeMessages(int)
I/art (4278): DoCall - void com.android.contacts.list.ProviderStatusWatcher.stop()
I/art (4278): DoCall - boolean com.android.contacts.list.ProviderStatusWatcher.isStarted()
I/art (4278): DoCall - void android.os.Handler.removeCallbacks(java.lang.Runnable)
I/art (4278): DoCall - android.content.ContentResolver com.android.contacts.ContactsActivity.getContentResolver()
I/art (4278): DoCall - void android.content.ContentResolver.unregisterContentObserver(android.database.ContentObserver)
I/art (4278): DoCall - void android.app.Activity.onPause()
I/art (4278): DoCall - void android.view.ViewGroup.drawableStateChanged()
I/art (4278): DoCall - void com.android.contacts.ContactsActivity.<init>()
I/art (4278): DoCall - void com.android.contacts.common.activity.TransactionSafeActivity.<init>()
I/art (4278): DoCall - void android.app.Activity.<init>()
I/art (4278): DoCall - void com.android.contacts.util.DialogManager.<init>(android.app.Activity)
I/art (4278): DoCall - void java.lang.Object.<init>()
[...]
Kiedy to się skończy:
[email protected]:/ # setprop target.app.pid 0
voila!
Przeciążenie nie jest zauważalne z punktu widzenia użytkownika, ale logcat zostanie szybko wypełniony.
PS: Ścieżki plików i nazwy pasują do wersji Androida 5 (Lollipop), będą prawdopodobnie inne w wersjach lepszych.
PS ': Jeśli ktoś chciałby wydrukować argumenty metod, radziłbym mu przyjrzeć się sztuce/runtime/utils.cc dla metody PrettyArguments i znaleźć jakąś praktyczną implementację gdzieś w kodzie.
Dziękuję bardzo za wyjaśnienie tego. Mam pytanie. Jeśli chcę załatać kod AOSP, jak wyjaśniłeś i zbudować obraz systemu Android dla emulatora, gdzie powinienem dodać opcję "tylko do tłumaczenia"? Nie mogłem znaleźć pliku device.mk dla emulatora. Uprzejmie proszę dać mi znać. – aMa
Jakie jest Twoje urządzenie docelowe? Mój był węzłem 5, więc moja ścieżka to /device/lge/hammerhead/device.mk. –
Sry, właśnie czytałem zbyt szybko. Nigdy nie próbowałem emulatora i prawdopodobnie napotkasz problemy z libcutils dla funkcji property_get. Czy próbowałeś już bez modyfikacji pliku device.mk? Powinien działać bez niego w najgorszym przypadku. Bez tego najgorszą rzeczą, jaka może się stać, jest to, że przegapisz niektóre z połączeń. –