藝術 TI

在 Android 8.0 及更高版本中,ART 工具介面 (ART TI) 公開了某些運行時內部結構,並使分析器和偵錯器能夠影響應用程式的執行時間行為。這可用於實現最先進的性能工具,這些工具是為在其他平台上實現本機代理而提供的。

運行時內部結構暴露給已載入到運行時進程中的代理程式。它們透過直接呼叫和回調與 ART 進行通訊。運行時支援多個代理,以便可以分離不同的正交分析關注點。代理程式可以在執行時間啟動時提供(當呼叫dalvikvmapp_process時),也可以附加到已經執行的進程。

由於偵測和修改應用程式及執行時間行為的能力非常強大,因此 ART TI 中整合了兩項安全措施:

  • 首先,公開代理介面 JVMTI 的程式碼是作為運行時插件實現的,而不是運行時的核心元件。插件載入可能會受到限制,因此可以阻止代理發現任何介面點。
  • 其次, ActivityManager類別和運行時進程都只允許代理程式附加到可偵錯應用程式。可調試的應用程式已由開發人員簽署並進行分析和檢測,並且不會分發給最終用戶。 Google Play 商店不允許分發可調試應用程式。這確保了正常的應用程式(包括核心組件)無法被偵測或操縱。

設計

儀表化應用程式中的一般流程和互連如圖 1所示。

Flow and interconnection in an instrumented app
圖 1.儀表化應用程式的流程和互連

ART 外掛程式libopenjdkjvmti公開了 ART TI,該 TI 旨在適應平台的需求和約束:

  • 類別重定義是基於Dex文件,僅包含單一類別定義,而不是類別文件。
  • 用於偵測和重新定義的 Java 語言 API 並未公開。

ART TI 也支援 Android Studio 分析器。

載入或附加代理

要在運行時啟動時附加代理,請使用以下命令載入 JVMTI 插件和給定代理:

dalvikvm -Xplugin:libopenjdkjvmti.so -agentpath:/path/to/agent/libagent.so …

在運行時啟動時載入代理程式時,沒有適當的安全措施,因此請記住,手動啟動的運行時允許在沒有安全措施的情況下進行完全修改。 (這允許 ART 測試。)

注意:這不適用於裝置上的普通應用程式(包括系統伺服器)。應用程式是從已經運行的 zygote 分叉出來的,並且 zygote 進程不允許載入代理。

若要將代理附加到已運行的應用程序,請使用以下命令:

adb shell cmd activity attach-agent [process]
/path/to/agent/libagent.so[=agent-options]

如果尚未載入 JVMTI 插件,則附加代理程式會載入插件和代理程式庫。

代理只能附加到標記為可偵錯的正在執行的應用程式(應用程式清單的一部分,在應用程式節點上將屬性android:debuggable設為true )。 ActivityManager類別和 ART 在允許附加代理之前都會執行檢查。 ActivityManager類別會檢查目前應用程式資訊(衍生自PackageManager類別資料)的可偵錯狀態,執行時間檢查其目前狀態(該狀態是在應用程式啟動時設定的)。

代理地點

運行時需要將代理程式載入到目前進程中,以便代理程式可以直接與其綁定並通訊。 ART 本身對於代理人來自的特定位置是不可知的。該字串用於dlopen呼叫。檔案系統權限和 SELinux 策略限制實際載入。

若要提供可由可偵錯應用程式執行的代理,請執行下列操作:

  • 將代理程式嵌入到應用程式 APK 的庫目錄中。
  • 使用run-as將代理複製到應用程式的資料目錄中。

蜜蜂

以下方法已新增至android.os.Debug

/**
     * Attach a library as a jvmti agent to the current runtime, with the given classloader
     * determining the library search path.
     * Note: agents may only be attached to debuggable apps. Otherwise, this function will
     * throw a SecurityException.
     *
     * @param library the library containing the agent.
     * @param options the options passed to the agent.
     * @param classLoader the classloader determining the library search path.
     *
     * @throws IOException if the agent could not be attached.
     * @throws a SecurityException if the app is not debuggable.
     */
    public static void attachJvmtiAgent(@NonNull String library, @Nullable String options,
            @Nullable ClassLoader classLoader) throws IOException {

其他 Android API

Attach-agent 指令是公開可見的。此命令將 JVMTI 代理程式附加到正在執行的進程:

adb shell 'am attach-agent com.example.android.displayingbitmaps
\'/data/data/com.example.android.displayingbitmaps/code_cache/libfieldnulls.so=Ljava/lang/Class;.name:Ljava/lang/String;\''

am start -Pam start-profiler/stop-profiler指令與 Attach-agent 指令類似。

JVMTI

此功能向代理程式(本機程式碼)公開 JVMTI API。重要的能力包括:

  • 重新定義一個類別。
  • 追蹤對象分配和垃圾收集。
  • 遵循物件的引用樹,迭代堆中的所有物件。
  • 檢查 Java 呼叫堆疊。
  • 掛起(和恢復)所有執行緒。

不同版本的 Android 可能會提供不同的功能。

相容性

此功能需要核心運行時支持,該支援僅在 Android 8.0 及更高版本上提供。設備製造商無需進行任何更改即可實現此功能。它是 AOSP 的一部分。

驗證

CTS 在 Android 8 及更高版本上測試以下內容:

  • 測試代理是否附加到可偵錯應用程序,以及是否無法附加到不可偵錯應用程式。
  • 測試所有已實作的 JVMTI API
  • 測試代理程式的二進位介面是否穩定

Android 9 及更高版本中新增了其他測試,並包含在這些版本的 CTS 測試中。