diff --git a/commands/sensors/README.md b/commands/sensors/README.md new file mode 100644 index 0000000..fdb70e6 --- /dev/null +++ b/commands/sensors/README.md @@ -0,0 +1,72 @@ +# `sensors` + +`sensors` is a Grease hardware command, not an Android experiment. Its job is to enumerate sensing hardware through the best available platform adapter while keeping the command meaning independent of that adapter. + +The first implementation is Android ARMv7. It reaches the public native Android sensor boundary through the phone's real `libandroid.so` and prints tab-separated metadata. + +A physical Android Go phone has now executed the exact cross-built artifact carried here and returned its real sensor list. The observed run reported `count 0x00000026` and included the phone's accelerometer plus the vendor's gesture/orientation sensors. That device-specific count and those names are evidence from one phone, not values to bake into tests. + +## Phone workflow + +Do not install Clang or the Android NDK on the phone. The phone is an execution target only: fetch the already-built ARMv7 executable, verify it, install it in the Termux command directory, and run `sensors`. + +The repository carries the executable as `sensors.armv7.b64` because this small artifact is stored through a text-content path. After decoding, its SHA-256 is: + +```text +9270b8ebd1243b388a17f24a5cad4883363ca7a5dd122431df2d2a7dc49c87f5 +``` + +It is a 3556-byte ARMv7 Thumb-2 PIE with `/system/bin/linker` as interpreter and `libandroid.so` as its only dynamic library dependency. + +A typical install is: + +```sh +base64 -d sensors.armv7.b64 > "$PREFIX/bin/sensors" +echo '9270b8ebd1243b388a17f24a5cad4883363ca7a5dd122431df2d2a7dc49c87f5 '"$PREFIX/bin/sensors" | sha256sum -c - +chmod 755 "$PREFIX/bin/sensors" +sensors +``` + +## Off-device build + +`sensors.c` is freestanding so the cross-build does not need Android headers or libc. It writes output with ARM Linux system calls and calls only the public Android sensor symbols it needs. + +`link-libandroid-stub.c` is link-time scaffolding only. It supplies symbol names and the `libandroid.so` SONAME to the off-device linker. The stub is not shipped to the phone; Android's dynamic linker loads the phone's real `libandroid.so`. + +The current artifact was produced with Clang/LLD 17: + +```sh +clang --target=armv7a-linux-gnueabi -march=armv7-a -mthumb \ + -ffreestanding -fPIC -fno-stack-protector -fno-builtin -nostdlib \ + -fuse-ld=lld -shared -Wl,-soname,libandroid.so -Wl,--no-undefined \ + -o /tmp/libandroid.so link-libandroid-stub.c + +clang --target=armv7a-linux-gnueabi -march=armv7-a -mthumb -Oz \ + -ffreestanding -fPIE -fno-stack-protector -fno-builtin -nostdlib \ + -c -o /tmp/sensors.o sensors.c + +clang --target=armv7a-linux-gnueabi -fuse-ld=lld -nostdlib \ + -Wl,-pie -Wl,--dynamic-linker=/system/bin/linker -Wl,-e,_start \ + -Wl,--hash-style=both -L/tmp /tmp/sensors.o -landroid -o sensors +``` + +The libc-free formatter is an implementation convenience, not part of the command semantics. The meaningful architectural choice is that the Android implementation uses the native sensor service boundary rather than a vendor HAL or raw kernel device. + +## Command family + +The next hardware commands should keep the same separation between program meaning and platform adapter: + +```text +sensors + enumerate available sensors + +read accelerometer + wait for one fresh acceleration measurement and print it + +watch accelerometer + stream acceleration measurements +``` + +Later adapters may use Linux IIO, a Termux:API bridge, 9P, FUSE, or another native system interface without changing those meanings. + +The ARM/Thumb compiler repository carries the same programs as backend sample targets. A hand-written C oracle or a physically working Android binary is not, by itself, evidence that IdriƧ generated that ARM/Thumb program. diff --git a/commands/sensors/link-libandroid-stub.c b/commands/sensors/link-libandroid-stub.c new file mode 100644 index 0000000..ecf5770 --- /dev/null +++ b/commands/sensors/link-libandroid-stub.c @@ -0,0 +1,10 @@ +void *ASensorManager_getInstance(void) { return 0; } +int ASensorManager_getSensorList(void *manager, const void ***list) { + (void)manager; + (void)list; + return 0; +} +const char *ASensor_getName(const void *sensor) { (void)sensor; return 0; } +const char *ASensor_getVendor(const void *sensor) { (void)sensor; return 0; } +int ASensor_getType(const void *sensor) { (void)sensor; return 0; } +int ASensor_getMinDelay(const void *sensor) { (void)sensor; return 0; } diff --git a/commands/sensors/sensors.armv7.b64 b/commands/sensors/sensors.armv7.b64 new file mode 100644 index 0000000..0fac04c --- /dev/null +++ b/commands/sensors/sensors.armv7.b64 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/commands/sensors/sensors.armv7.sha256 b/commands/sensors/sensors.armv7.sha256 new file mode 100644 index 0000000..2cfc594 --- /dev/null +++ b/commands/sensors/sensors.armv7.sha256 @@ -0,0 +1 @@ +9270b8ebd1243b388a17f24a5cad4883363ca7a5dd122431df2d2a7dc49c87f5 sensors diff --git a/commands/sensors/sensors.c b/commands/sensors/sensors.c new file mode 100644 index 0000000..557e27f --- /dev/null +++ b/commands/sensors/sensors.c @@ -0,0 +1,79 @@ +typedef struct ASensorManager ASensorManager; +typedef struct ASensor ASensor; +typedef const ASensor *const *ASensorList; + +extern ASensorManager *ASensorManager_getInstance(void); +extern int ASensorManager_getSensorList(ASensorManager *, ASensorList *); +extern const char *ASensor_getName(const ASensor *); +extern const char *ASensor_getVendor(const ASensor *); +extern int ASensor_getType(const ASensor *); +extern int ASensor_getMinDelay(const ASensor *); + +static long write_bytes(int fd, const char *data, unsigned int count) { + register long r0 __asm__("r0") = fd; + register long r1 __asm__("r1") = (long)data; + register long r2 __asm__("r2") = count; + register long r7 __asm__("r7") = 4; + __asm__ volatile("svc 0" : "+r"(r0) : "r"(r1), "r"(r2), "r"(r7) : "memory"); + return r0; +} + +__attribute__((noreturn)) static void exit_process(int status) { + register long r0 __asm__("r0") = status; + register long r7 __asm__("r7") = 1; + __asm__ volatile("svc 0" : : "r"(r0), "r"(r7) : "memory"); + for (;;) { } +} + +static unsigned int text_length(const char *text) { + unsigned int n = 0; + if (!text) return 0; + while (text[n]) ++n; + return n; +} + +static void write_text(const char *text) { + if (text) write_bytes(1, text, text_length(text)); +} + +static void write_hex(unsigned int value) { + char out[10]; + static const char digits[] = "0123456789abcdef"; + out[0] = '0'; out[1] = 'x'; + for (unsigned int i = 0; i < 8; ++i) { + unsigned int shift = 28 - i * 4; + out[2 + i] = digits[(value >> shift) & 15u]; + } + write_bytes(1, out, 10); +} + +static int run(void) { + ASensorManager *manager = ASensorManager_getInstance(); + if (!manager) { + write_text("sensor manager unavailable\n"); + return 2; + } + + ASensorList list = 0; + int count = ASensorManager_getSensorList(manager, &list); + if (count < 0 || !list) { + write_text("sensor list unavailable\n"); + return 3; + } + + write_text("count\t"); write_hex((unsigned int)count); write_text("\n"); + write_text("index\ttype\tmin_delay_us\tname\tvendor\n"); + for (int i = 0; i < count; ++i) { + const ASensor *sensor = list[i]; + write_hex((unsigned int)i); write_text("\t"); + write_hex((unsigned int)ASensor_getType(sensor)); write_text("\t"); + write_hex((unsigned int)ASensor_getMinDelay(sensor)); write_text("\t"); + write_text(ASensor_getName(sensor)); write_text("\t"); + write_text(ASensor_getVendor(sensor)); write_text("\n"); + } + return 0; +} + +void _start(void) { + exit_process(run()); +}