fix(adb): accept Android Java float spellings unchanged

Use Float.valueOf grammar at shared admission and retain selected spelling through am --ef. Validated scientific notation, malformed controls and exact MCP forwarding with a source-owned ADB fixture; no device execution.

Fixes #6796
This commit is contained in:
morluto committed 2026-10-24 01:00:14 +08:00
1 parent d4415444c4
commit 42e785925c
4 files changed
+27 -5

No files matched your search

+8 -1
View File
@@ -99,6 +99,12 @@ it("admits empty string extras and validates typed extra text at domain admissio
{ type: "int", value: "-2147483648" },
{ type: "long", value: "9007199254740993" },
{ type: "float", value: "-1.25" },
{ type: "float", value: "1e-3" },
{ type: "float", value: "1E-3" },
{ type: "float", value: ".5" },
{ type: "float", value: "1." },
{ type: "float", value: "0x1.8p1" },
{ type: "float", value: "NaN" },
] as const;
for (const { type, value } of accepted)
expect(
@@ -112,7 +118,8 @@ it("admits empty string extras and validates typed extra text at domain admissio
{ type: "boolean", value: "True" },
{ type: "int", value: "1.5" },
{ type: "long", value: "" },
{ type: "float", value: "1e3" },
{ type: "float", value: "garbage" },
{ type: "float", value: "0x1.8" },
] as const;
for (const { type, value } of rejected) {
const result = adbInputSchemas.start_adb_activity.safeParse({
+11 -2
View File
@@ -59,6 +59,10 @@ const activityExtraStringValueSchema = z
.max(2048)
.regex(/^[^\x00]*$/u, "Extra values cannot contain NUL");
const activityExtraNonEmptyValueSchema = activityExtraStringValueSchema.min(1);
// Android's `am start --ef` parses this text with Float.valueOf. Keep the
// caller's spelling intact while admitting Java FloatValue forms.
const javaFloatValuePattern =
/^[\x01-\x20]*[+-]?(?:NaN|Infinity|(?:(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[fFdD]?|0[xX](?:[\da-fA-F]+(?:\.[\da-fA-F]*)?|\.[\da-fA-F]+)[pP][+-]?\d+[fFdD]?))[\x01-\x20]*$/u;
const activityExtraSchema = z.discriminatedUnion("type", [
z.strictObject({
key: activityExtraKeySchema,
@@ -92,8 +96,13 @@ const activityExtraSchema = z.discriminatedUnion("type", [
key: activityExtraKeySchema,
type: z.literal("float").describe("Float extra value type"),
value: activityExtraNonEmptyValueSchema
.regex(/^-?\d+(\.\d+)?$/u, "Float extra values must be a number")
.describe("Float extra value as decimal text"),
.regex(
javaFloatValuePattern,
"Float extra value must be valid Java float text",
)
.describe(
"Float extra text parsed by Android am without changing its spelling",
),
}),
]);
+5 -1
View File
@@ -244,7 +244,11 @@ it.each([
["boolean:key:yes", "invalid_request"],
["int:key:1.5", "invalid_request"],
["long:key:1.5", "invalid_request"],
["float:key:1e3", "invalid_request"],
["float:key:garbage", "invalid_request"],
["float:key:1e-3", "capability_unavailable"],
["float:key:1E-3", "capability_unavailable"],
["float:key:.5", "capability_unavailable"],
["float:key:1.", "capability_unavailable"],
["boolean:key:false", "capability_unavailable"],
["int:key:-3", "capability_unavailable"],
["long:key:9007199254740993", "capability_unavailable"],
+3 -1
View File
@@ -160,7 +160,7 @@ const assertAdvertisedActivityExtras = async (
["boolean", "yes"],
["int", "1.5"],
["long", ""],
["float", "1e3"],
["float", "garbage"],
])
expect(
validateInput({ ...input, extras: [{ key: "invalid", type, value }] }),
@@ -224,6 +224,7 @@ it
extras: [
{ key: "mode", type: "string" as const, value: "test" },
{ key: "empty", type: "string" as const, value: "" },
{ key: "scale", type: "float" as const, value: "1e-3" },
],
};
const success = await client.callTool({
@@ -312,6 +313,7 @@ it
"-n com.example/.Main",
"--es mode test",
"--es empty ''",
"--ef scale 1e-3",
]),
].join(" "),
),