[Feature] (disaggregated): WindowKind::HostFrame - the host-framed surface crosses the wire

The last thing between the host-framed surface and a run: the sub-byte on the wire that names it.
ServerOwned had one (7) and the host frame had none, so the encoder refused the op with
UnknownWindowKind - a correct refusal, and the reason the first run of MOBILEGL_IPC_SURFACE=host
failed in the codec rather than anywhere near the pixels.

 - protocol.fbs: WindowKind::HostFrame = 8, appended, legal on CreateWindowSurface only and always
   with nativeToken 0 - the same rules ServerOwned carries, for the same reason: no pointer of any
   process's window system crosses (Rule G/H).
 - SurfaceRefusal: HostFrameOnSetWindowHandle = 5, its own code rather than reusing the
   server-owned one: a refusal that names the wrong owner sends the next reader to the wrong place.
 - SurfaceOpCodec: the encode and decode arms, the two wire errors that go with them
   (HostFrameTokenNotZero latches as corruption, HostFrameOnSetWindowHandle is a named refusal), and
   the range bound that had ServerOwned as its upper limit now ends at HostFrame.
 - protocol_generated.h regenerated with the pinned submodule's flatc (scripts/gen_protocol.py),
   diff being exactly the two appended enumerators.

Both ends must be rebuilt together, as any protocol revision here: the container's client and the
device's server went out with this on either side.
This commit is contained in:
gold
2026-10-01 01:26:02 +08:00
parent ead7a10b68
commit 1ae7a8eaa4
6 changed files with 61 additions and 12 deletions
+33 -2
View File
@@ -58,6 +58,11 @@ namespace MobileGL::MG_Remote {
static_assert(static_cast<Uint8>(::MobileGL::Wire::WindowKind::MetalLayer) == 6);
// P12's append, on the same terms: the value is wire ABI.
static_assert(static_cast<Uint8>(::MobileGL::Wire::WindowKind::ServerOwned) == 7);
static_assert(static_cast<Uint8>(::MobileGL::Wire::WindowKind::HostFrame) == 8);
static_assert(static_cast<Uint8>(::MobileGL::Wire::SurfaceRefusal::HostFrameOnSetWindowHandle) ==
static_cast<Uint8>(Server::SurfaceRefusalCode::HostFrameOnSetWindowHandle));
static_assert(Server::kHostFrameWindowBackend > Server::kServerOwnedWindowBackend,
"kHostFrameWindowBackend must not collide with the server-owned tag");
// The frame's refusal codes ARE the wire's SurfaceRefusal (SurfaceControlFrame.h), pinned
// value by value so a schema edit that renumbers either side fails here.
using Server::SurfaceRefusalCode;
@@ -94,6 +99,8 @@ namespace MobileGL::MG_Remote {
case SurfaceWireError::AndroidNativeWindowArrived: return "AndroidNativeWindowArrived";
case SurfaceWireError::ServerOwnedTokenNotZero: return "ServerOwnedTokenNotZero";
case SurfaceWireError::ServerOwnedOnSetWindowHandle: return "ServerOwnedOnSetWindowHandle";
case SurfaceWireError::HostFrameTokenNotZero: return "HostFrameTokenNotZero";
case SurfaceWireError::HostFrameOnSetWindowHandle: return "HostFrameOnSetWindowHandle";
}
return "<unknown SurfaceWireError>";
}
@@ -167,6 +174,15 @@ namespace MobileGL::MG_Remote {
}
windowKind = ::MobileGL::Wire::WindowKind::ServerOwned;
nativeToken = 0;
} else if (frame.windowBackend == Server::kHostFrameWindowBackend) {
// MOBILEGL_IPC_SURFACE=host: the frames are the DISPLAY HOST's, taken by the
// server from the host frame bridge. As for the server-owned tag - a creation
// only, and the token is 0 whatever the frame carried.
if (frame.kind != SurfaceControlOp::CreateWindowSurface) {
return SurfaceWireError::HostFrameOnSetWindowHandle;
}
windowKind = ::MobileGL::Wire::WindowKind::HostFrame;
nativeToken = 0;
} else if (!WireWindowKindForWindowBackend(
static_cast<MG_Backend::WindowBackend>(frame.windowBackend), &windowKind)) {
return SurfaceWireError::UnknownWindowKind;
@@ -213,6 +229,21 @@ namespace MobileGL::MG_Remote {
*frame = decoded;
return SurfaceWireError::None;
}
if (op.windowKind() == ::MobileGL::Wire::WindowKind::HostFrame) {
// MOBILEGL_IPC_SURFACE=host. As above: a creation only, and a token of 0
// only - anything else is a value from the peer's window system trying to
// cross (Rule G), which is corruption rather than a refusal.
if (kind != SurfaceControlOp::CreateWindowSurface) {
return SurfaceWireError::HostFrameOnSetWindowHandle;
}
if (op.nativeToken() != 0) {
return SurfaceWireError::HostFrameTokenNotZero;
}
decoded.windowBackend = Server::kHostFrameWindowBackend;
decoded.nativeToken = 0;
*frame = decoded;
return SurfaceWireError::None;
}
if (op.windowKind() == ::MobileGL::Wire::WindowKind::AndroidNativeWindow) {
// The one refusal that is not corruption: the window kind is LEGAL and the token
// is an ANativeWindow*, which names memory in the CLIENT's process. Real window
@@ -225,10 +256,10 @@ namespace MobileGL::MG_Remote {
}
MG_Backend::WindowBackend backend;
if (!WindowBackendForWireWindowKind(op.windowKind(), &backend)) {
// THE UPPER BOUND IS THE LAST APPENDED KIND (P12: ServerOwned), for the reason
// THE UPPER BOUND IS THE LAST APPENDED KIND (P12: HostFrame), for the reason
// SurfaceControlOpForWireKind's bound gives.
return ::flatbuffers::IsOutRange(op.windowKind(), ::MobileGL::Wire::WindowKind::None,
::MobileGL::Wire::WindowKind::ServerOwned)
::MobileGL::Wire::WindowKind::HostFrame)
? SurfaceWireError::UnknownWindowKind
: SurfaceWireError::WindowKindNamesNoBackend;
}
@@ -68,6 +68,9 @@ namespace MobileGL::MG_Remote {
// CreateWindowSurface only, and only with nativeToken 0:
ServerOwnedTokenNotZero, // -> Fatal{ProtocolCorruption, "SurfaceOp.nativeToken"}, latched
ServerOwnedOnSetWindowHandle, // -> a NAMED REFUSAL (reply ok=false), not a latch
// MOBILEGL_IPC_SURFACE=host, the same two rules for the other on-screen shape:
HostFrameTokenNotZero, // -> Fatal{ProtocolCorruption, "SurfaceOp.nativeToken"}, latched
HostFrameOnSetWindowHandle, // -> a NAMED REFUSAL (reply ok=false), not a latch
};
const char* SurfaceWireErrorName(SurfaceWireError error);
@@ -341,11 +341,12 @@ enum class WindowKind : uint8_t {
Pbuffer = 5,
MetalLayer = 6,
ServerOwned = 7,
HostFrame = 8,
MIN = None,
MAX = ServerOwned
MAX = HostFrame
};
inline const WindowKind (&EnumValuesWindowKind())[8] {
inline const WindowKind (&EnumValuesWindowKind())[9] {
static const WindowKind values[] = {
WindowKind::None,
WindowKind::AndroidNativeWindow,
@@ -354,13 +355,14 @@ inline const WindowKind (&EnumValuesWindowKind())[8] {
WindowKind::Surfaceless,
WindowKind::Pbuffer,
WindowKind::MetalLayer,
WindowKind::ServerOwned
WindowKind::ServerOwned,
WindowKind::HostFrame
};
return values;
}
inline const char * const *EnumNamesWindowKind() {
static const char * const names[9] = {
static const char * const names[10] = {
"None",
"AndroidNativeWindow",
"X11",
@@ -369,13 +371,14 @@ inline const char * const *EnumNamesWindowKind() {
"Pbuffer",
"MetalLayer",
"ServerOwned",
"HostFrame",
nullptr
};
return names;
}
inline const char *EnumNameWindowKind(WindowKind e) {
if (::flatbuffers::IsOutRange(e, WindowKind::None, WindowKind::ServerOwned)) return "";
if (::flatbuffers::IsOutRange(e, WindowKind::None, WindowKind::HostFrame)) return "";
const size_t index = static_cast<size_t>(e);
return EnumNamesWindowKind()[index];
}
@@ -386,35 +389,38 @@ enum class SurfaceRefusal : uint8_t {
NoServerWindow = 2,
SurfaceModeMismatch = 3,
ServerOwnedOnSetWindowHandle = 4,
HostFrameOnSetWindowHandle = 5,
MIN = None,
MAX = ServerOwnedOnSetWindowHandle
MAX = HostFrameOnSetWindowHandle
};
inline const SurfaceRefusal (&EnumValuesSurfaceRefusal())[5] {
inline const SurfaceRefusal (&EnumValuesSurfaceRefusal())[6] {
static const SurfaceRefusal values[] = {
SurfaceRefusal::None,
SurfaceRefusal::NoServerDisplay,
SurfaceRefusal::NoServerWindow,
SurfaceRefusal::SurfaceModeMismatch,
SurfaceRefusal::ServerOwnedOnSetWindowHandle
SurfaceRefusal::ServerOwnedOnSetWindowHandle,
SurfaceRefusal::HostFrameOnSetWindowHandle
};
return values;
}
inline const char * const *EnumNamesSurfaceRefusal() {
static const char * const names[6] = {
static const char * const names[7] = {
"None",
"NoServerDisplay",
"NoServerWindow",
"SurfaceModeMismatch",
"ServerOwnedOnSetWindowHandle",
"HostFrameOnSetWindowHandle",
nullptr
};
return names;
}
inline const char *EnumNameSurfaceRefusal(SurfaceRefusal e) {
if (::flatbuffers::IsOutRange(e, SurfaceRefusal::None, SurfaceRefusal::ServerOwnedOnSetWindowHandle)) return "";
if (::flatbuffers::IsOutRange(e, SurfaceRefusal::None, SurfaceRefusal::HostFrameOnSetWindowHandle)) return "";
const size_t index = static_cast<size_t>(e);
return EnumNamesSurfaceRefusal()[index];
}
+7
View File
@@ -274,6 +274,12 @@ enum WindowKind : ubyte {
// SurfaceView) and has none of its own to name, so `nativeToken` is always 0 and no pointer
// crosses (Rule G/H). Legal on CreateWindowSurface only; SetWindowHandle may not name it.
ServerOwned = 7,
// P12, appended: the OTHER on-screen shape, and its mirror image. The client names no
// window here either - but the frames are the DISPLAY HOST's: it allocates them, offers
// each one over the host frame bridge, and puts them on the glass itself, while the
// server draws into them. `nativeToken` is always 0, as for ServerOwned, and it is legal
// on CreateWindowSurface only.
HostFrame = 8,
}
// P12, appended: WHY A SURFACE OP WAS DECLINED, so the client can name the refusal in its own log
@@ -285,6 +291,7 @@ enum SurfaceRefusal : ubyte {
NoServerWindow = 2, // the server owns a display, but no window came within its wait
SurfaceModeMismatch = 3, // the session's surface mode (on-screen / offscreen) is the other one
ServerOwnedOnSetWindowHandle = 4, // SetWindowHandle named the server's own window
HostFrameOnSetWindowHandle = 5, // SetWindowHandle named the display host's frames
}
table SurfaceOp {
@@ -60,6 +60,7 @@ namespace MobileGL::MG_Remote::Server {
case SurfaceRefusalCode::NoServerWindow: return "NoServerWindow";
case SurfaceRefusalCode::SurfaceModeMismatch: return "SurfaceModeMismatch";
case SurfaceRefusalCode::ServerOwnedOnSetWindowHandle: return "ServerOwnedOnSetWindowHandle";
case SurfaceRefusalCode::HostFrameOnSetWindowHandle: return "HostFrameOnSetWindowHandle";
}
return "<unknown SurfaceRefusalCode>";
}
@@ -105,6 +105,7 @@ namespace MobileGL::MG_Remote::Server {
NoServerWindow = 2, // a display, but no window within the wait
SurfaceModeMismatch = 3, // D4: the session's surface mode is the other one
ServerOwnedOnSetWindowHandle = 4, // SetWindowHandle named the server's own window
HostFrameOnSetWindowHandle = 5, // SetWindowHandle named the display host's frames
};
const char* SurfaceRefusalCodeName(SurfaceRefusalCode code);