Skip to content

Agent API ​

ClassyShark exposes two complementary Agent API modes:

  • Headless mode: archive analysis without creating a Swing window. It can run on a server without a display.
  • GUI mode: controls a live Swing window through a JSON-over-stdio bridge. Human interaction remains available.

Both modes use one JSON request per line and one JSON response per line:

json
{"command":"agent.capabilities","params":{}}

Successful responses contain status: "ok"; failures contain status: "error" and an error code.

Headless mode ​

Start the protocol without opening the GUI:

bash
java -jar ClassyShark.jar -agent-stdio

The archive.* and apk.* commands are pure analysis operations. They accept an archive path in params.path and do not require a GUI process or display server.

CommandPurpose
archive.list_classesList classes, with optional query, offset, and limit
archive.get_classTranslate one class (className)
archive.get_manifestRead the APK manifest
archive.list_methodsList DEX methods
archive.list_stringsList DEX strings
archive.is_multidexDetect standard and custom multidex
archive.method_countsExport tree or flat method counts (flat)
archive.inspect_apkInspect APK structure
archive.exportExport analysis files to outputDir
archive.list_componentsList archive components
archive.get_entryTranslate/read an archive entry (entry)
archive.get_class_depsList dependencies of className
apk.dashboardReturn APK dashboard data
apk.check_java_depsReturn Java dependency warnings
apk.check_manifestReturn manifest recommendations/issues

For embedding without stdio, AgentCommandDispatcher.dispatch(String json) exposes the same service in-process. The underlying HeadlessAgentService contains no Swing/AWT dependency.

GUI mode ​

Start a GUI and the Agent bridge together:

bash
java -jar ClassyShark.jar -agent-gui-stdio

GUI commands require an active GUI. Archive loading, navigation, and search are asynchronous by default; the *_and_wait variants are recommended when an Agent needs a deterministic result.

Read-only state ​

CommandPurpose
gui.statusRead GUI/archive/display state and human activity status
gui.get_display_contentRead current display mode, class, and translated content
gui.get_class_listRead classes in the loaded archive, with pagination/filtering
gui.get_filtered_classesRead the current search result list
gui.captureCapture the visible right-hand GUI panel as a base64 PNG
gui.status.activeTabRead which tab (classes or methods_count) is shown

Control ​

CommandPurpose
gui.open_archiveOpen an archive asynchronously
gui.navigate_toNavigate to a class asynchronously
gui.searchUpdate the search field asynchronously
gui.go_backReturn to the class list
gui.view_top_classOpen the top autocomplete result
gui.exportExport the current GUI selection/archive
gui.load_mappingsLoad a mapping file (path)
gui.toggle_treeShow or hide the class tree (visible)
gui.set_tabSwitch the right-hand view to classes or methods_count

Deterministic control ​

CommandPurpose
gui.open_and_waitOpen an archive and wait for loading (timeoutMs)
gui.wait_for_loadWait for an already-started archive load
gui.navigate_and_readNavigate and return translated display content
gui.search_and_waitSearch and return the resulting class list

Co-existence contract ​

  • Agent commands are dispatched to the Swing event queue; the Agent protocol thread does not block the EDT.
  • Before disruptive operations, inspect gui.status.humanRecentlyActive. If it is true, defer the operation; it means a human typed within the five-second activity window.
  • Prefer read-only commands whenever possible.
  • Use timeout parameters and handle timedOut: true rather than assuming a result is ready.
  • GUI state is synchronized back from the panel after archive, navigation, search, back, and error transitions.

gui.status includes displayMode (IDLE, CLASS_LIST, INSIDE_CLASS, SEARCH_RESULTS, or ERROR), activeTab (classes or methods_count), leftPanelVisible, archiveLoaded, classCount, currentClass, and human activity fields. gui.capture returns {mime: "image/png", encoding: "base64", image: "..."} for the currently visible right-hand panel; it returns gui_not_visible when the component has no renderable size.

Capability discovery ​

Use agent.capabilities at startup to discover the protocol version and available commands (current protocol is classyshark-agent-v1).

The advertised command list is mode-specific:

  • Headless mode returns only the headless verbs (agent.capabilities plus archive.* and apk.*).
  • GUI mode returns the full surface (headless + gui.*).

Calling a gui.* command in headless mode returns error.code gui_not_available with guidance to relaunch with -agent-gui-stdio.

Architecture ​

The two modes are backed by two isolated services in agent/:

  • HeadlessAgentService — the pure analysis service. It has no GUI/Swing dependency, so it can run on a headless server and be packaged into a GUI-free jar.
  • GuiAgentService — owns the gui.* verbs and talks to the live Swing window via GuiBridge. It is only reachable in GUI mode.

Entry points:

  • -agent-stdio → HeadlessStdioMain → HeadlessAgentService (never touches GUI).
  • -agent-gui-stdio → AgentStdioMain → combined router (AgentCommandDispatcher.COMBINED).

For in-process embedding:

  • Headless-only: call HeadlessAgentService.invoke(request) directly.
  • Headless + GUI: use AgentCommandDispatcher.dispatch(json).

最后更新:

基于 Apache 2.0 协议发布