Skip to content

Livestream server - #226

Open
todi1856 wants to merge 10 commits into
masterfrom
livestream-server
Open

todi1856 wants to merge 10 commits into
masterfrom
livestream-server

Conversation

@todi1856

@todi1856 todi1856 commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

This is a cherry pick from - #224, since that PR is too big.

This PR carries only the parts that no Editor UI depends on, so that #224 can be rebased onto it and reviewed as the Editor change alone.

What is here:

Area What it is
External/UnityLogcatServer The on-device server. A dexed jar started by app_process as the shell user - no manifest, no activity - which is what lets it call the hidden display mirroring APIs and hold INJECT_EVENTS. It mirrors a display into an ImageReader (DisplayManagerGlobal.createVirtualDisplay, falling back to SurfaceControl.createDisplay), encodes each frame as JPEG and writes it to an abstract unix socket; the same socket carries touch, scroll, key and text messages back. JPEG rather than H.264 because the Editor has no reachable video decoder, and a JPEG frame goes straight into Texture2D.LoadImage.
.yamato/build-server-jar.yml, Tools/CI/Settings/UnityMobileLogcatSettings.cs The jar is a build output and is not committed, so a clone has none. A build_server_jar job produces it and the package pack job now depends on it, which is what puts it in the tarball the test jobs install.
AndroidLogcatUtilities.RunGradle Runs a Gradle task behind a cancelable progress bar, taking the JDK and SDK from Preferences > External Tools rather than from the environment, streaming Gradle's output to Editor.log and killing the process tree - launcher script and daemon both - on cancel or timeout. Nothing calls it on this branch; the debug button that builds the jar with it is in #224.
Tools/CI Cookbook project moved to net10.0, with global.json pinned to SDK 10 to match.

Nothing in this PR is reachable by a user: with the Editor side still on #224, the jar ships in the package and is never started.

todi1856 and others added 3 commits September 30, 2026 14:47
A small Java server, built with Gradle into a dex jar and pushed to the device,
that mirrors a display into an ImageReader, encodes each frame as JPEG and writes
it to an abstract unix socket. It also reads control messages back up the same
socket and injects touch, scroll, key and text events.

The jar is a build output and is not committed.

Cherry picked from the livestream branch, at its latest state: the null
virtualDisplay fix and the protocol version reset are folded in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The jar the live stream pushes to the device is a build output and is not
committed, so a clone has none. A build_server_jar job produces it and the pack
job now depends on it, which is also what puts it in the tarball the test jobs
install.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@u-pr u-pr Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Harness Review

Needs changes

The change adds an on-device MJPEG server and wires its jar into package packing, but the mirroring call and several control-event paths behave incorrectly for supported devices or valid inputs.

Reviewed commit b90bedb

🤖 Helpful? 👍/👎

Comment thread Tools/CI/UnityMobileLogcat.Cookbook.csproj
todi1856 and others added 3 commits September 30, 2026 14:56
RunGradle runs a task in a Gradle project behind a cancelable progress bar,
taking the JDK and SDK from Preferences > External Tools rather than from the
environment, streaming Gradle's output to Editor.log as it arrives and killing
the process tree - launcher script and daemon both - when a build is cancelled
or runs past its timeout.

Nothing calls it on this branch yet; the live stream's debug button that builds
the server jar stayed behind on the livestream branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@todi1856

Copy link
Copy Markdown
Member Author

/review

@u-pr u-pr Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Harness Review

Needs changes

The new server builds a package artifact and adds display capture and control handling; the frame conversion path can discard valid images on devices whose image rows have padding.

Reviewed commit 34ce873

🤖 Helpful? 👍/👎

@todi1856

Copy link
Copy Markdown
Member Author

/review

@u-pr u-pr Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Harness Review

Needs changes

The change adds an on-device streaming server and a CI path for packaging its jar, but the new lifecycle and input paths have reachable failures.

Reviewed commit b05b79d

🤖 Helpful? 👍/👎

Comment thread com.unity.mobile.android-logcat/Editor/AndroidLogcatUtilities.cs
@todi1856

Copy link
Copy Markdown
Member Author

/review

@u-pr u-pr Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Harness Review

Ship it

The change adds an on-device JPEG streaming server and wires its generated jar into package packing. I examined the build and artifact paths, control protocol, and capture lifecycle and found no new actionable issues beyond those previously reported.

Reviewed commit c36685d

⚠️ Earlier blocking findings with unresolved threads: 2. The verdict above does not cover them; resolve each thread after addressing it.

🤖 Helpful? 👍/👎

LocalSocket socket = null;
ScreenStreamer streamer = null;
try {
socket = accept(serverSocket, options.getConnectTimeoutMs());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude suggests to reject unwanted connections and to add this after accept.

            // adbd opens `adb forward` connections, as shell (2000) or root (0). Every app has its own uid >= 10000.
            int uid = socket.getPeerCredentials().getUid();
            if (uid != 0 && uid != 2000) {
                throw new IOException("Rejected a connection from uid " + uid + ", only adb may connect");
            }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

  private static void rejectUnlessAdb(LocalSocket socket) throws IOException {
        int uid = socket.getPeerCredentials().getUid();
        if (uid != ROOT_UID && uid != SHELL_UID) {
            throw new IOException("Rejected a connection from uid " + uid + ", only adb may connect");
        }
    }

characterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
}

KeyEvent[] events = characterMap.getEvents(text.toCharArray());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readme says that "non-US layouts work", but in reality if text contains non-ASCII characters, getEvents returns null, so the whole string would be lost
available options are:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude supposedly fixed this..


private void startSession(DisplayInfo info) throws IOException {
synchronized (sessionLock) {
displaySize = info.getSize();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor possibility of race condition, device rotated while close method is called, making handler null
makes sense to check for stopped and return early.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@todi1856
todi1856 requested a review from BorisShir October 1, 2026 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants