简体   繁体   中英

How to do GPIO on Android Things bypassing Java

I've been trying to access GPIO on Raspberry Pi with Android things using NDK, but after trying several approaches I always find some kind of security wall preventing me from accessing it.

The motivation is the sluggish speed I'm getting from GPIO using the Java API. As a basic reference I was able to toggle it on and off at about 2KHz, which happens to be the poorest among this list . See also What is Android Things Raspberry Pi GPIO max frequency? , where so far there's no answer and where I added a comment about java speed. In fact this work was motivated by the results I got when checking for that question.

The best approach so far is trying something similar to what would take for sysfs under Debian. To that extent, the code seems fair but after running as root, installing the app as system app (by moving it to /system/app) and chmod a+rw several different things under both /sys/class/gpio/ and /sys/class/gpio/gpio24/ and also /dev/gpiomem this was what I got:

01-27 12:54:47.069  8412  8412 I NativeHelper: Call native = hello from helper java class
01-27 12:54:47.079  8412  8412 I NativeHelper: Open pin true
01-27 12:54:47.080  8412  8412 F libc    : Fatal signal 4 (SIGILL), code 1, fault addr 0xaf2e039c in tid 8412 (le.thingssample)
01-27 12:54:47.081   128   128 W         : debuggerd: handling request: pid=8412 uid=10028 gid=10028 tid=8412
01-27 12:54:47.066  8412  8412 I le.thingssample: type=1400 audit(0.0:211): avc: denied { write } for name="export" dev="sysfs" ino=854 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1
01-27 12:54:47.076  8412  8412 I le.thingssample: type=1400 audit(0.0:212): avc: denied { open } for path="/sys/class/gpio/export" dev="sysfs" ino=854 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1
01-27 12:54:47.166  8427  8427 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-27 12:54:47.166  8427  8427 F DEBUG   : Build fingerprint: 'generic/iot_rpi3/rpi3:7.0/NIF73/3565696:userdebug/test-keys'
01-27 12:54:47.166  8427  8427 F DEBUG   : Revision: '0'
01-27 12:54:47.166  8427  8427 F DEBUG   : ABI: 'arm'
01-27 12:54:47.167  8427  8427 F DEBUG   : pid: 8412, tid: 8412, name: le.thingssample  >>> com.amazingapps.sample.thingssample <<<
01-27 12:54:47.167  8427  8427 F DEBUG   : signal 4 (SIGILL), code 1 (ILL_ILLOPC), fault addr 0xaf2e039c
01-27 12:54:47.167  8427  8427 F DEBUG   :     r0 00000000  r1 b1f5e59f  r2 b1f5e59f  r3 af2e1c55
01-27 12:54:47.167  8427  8427 F DEBUG   :     r4 00000000  r5 be8e35fc  r6 acca3230  r7 be8e35d8
01-27 12:54:47.167  8427  8427 F DEBUG   :     r8 be8e36f8  r9 acc85400  sl 00000000  fp be8e3684
01-27 12:54:47.168  8427  8427 F DEBUG   :     ip be8e3590  sp be8e3598  lr ae7fbd2b  pc af2e039c  cpsr 60000030
01-27 12:54:47.170  8427  8427 F DEBUG   :
01-27 12:54:47.170  8427  8427 F DEBUG   : backtrace:
01-27 12:54:47.170  8427  8427 F DEBUG   :     #00 pc 0000139c  /data/app/com.amazingapps.sample.thingssample-1/lib/arm/libsample.so (Java_com_amazingapps_sample_thingssample_ndk_NativeHelper_doAll+59)
01-27 12:54:47.170  8427  8427 F DEBUG   :     #01 pc 002c8cb3  /data/app/com.amazingapps.sample.thingssample-1/oat/arm/base.odex (offset 0x2af000)
01-27 12:54:48.133   408  8432 W ActivityManager:   Force finishing activity com.amazingapps.sample.thingssample/.view.MainActivity
01-27 12:54:48.137   128   128 W         : debuggerd: resuming target 8412
01-27 12:54:48.138   408   427 I BootReceiver: Copying /data/tombstones/tombstone_02 to DropBox (SYSTEM_TOMBSTONE)
01-27 12:54:48.228  8433  8433 W crash_reporter: Received crash notification for app_process32[8412] sig 4, user 10028 (handling)
01-27 12:54:48.233  8433  8433 I crash_reporter: State of crashed process [8412]: S (sleeping)
01-27 12:54:48.226  8433  8433 I crash_reporter: type=1400 audit(0.0:213): avc: denied { search } for name="8412" dev="proc" ino=214991 scontext=u:r:crash_reporter:s0 tcontext=u:r:untrusted_app:s0:c512,c768 tclass=dir permissive=1
01-27 12:54:48.226  8433  8433 I crash_reporter: type=1400 audit(0.0:214): avc: denied { read } for name="exe" dev="proc" ino=217417 scontext=u:r:crash_reporter:s0 tcontext=u:r:untrusted_app:s0:c512,c768 tclass=lnk_file permissive=1
01-27 12:54:48.226  8433  8433 I crash_reporter: type=1400 audit(0.0:215): avc: denied { read } for scontext=u:r:crash_reporter:s0 tcontext=u:r:untrusted_app:s0:c512,c768 tclass=file permissive=1
01-27 12:54:48.226  8433  8433 I crash_reporter: type=1400 audit(0.0:216): avc: denied { open } for path="/proc/8412/status" dev="proc" ino=216902 scontext=u:r:crash_reporter:s0 tcontext=u:r:untrusted_app:s0:c512,c768 tclass=file permissive=1
01-27 12:54:48.226  8433  8433 I crash_reporter: type=1400 audit(0.0:217): avc: denied { getattr } for path="/proc/8412/status" dev="proc" ino=216902 scontext=u:r:crash_reporter:s0 tcontext=u:r:untrusted_app:s0:c512,c768 tclass=file permissive=1
01-27 12:54:48.672   408   422 W ActivityManager: Activity pause timeout for ActivityRecord{f2233fb u0 com.amazingapps.sample.thingssample/.view.MainActivity t86 f}

By chmod a+rw /sys/class/gpio/export at least I got a difference and could open and close the pin, verified by the method return value and also checking the creation of /sys/class/gpio/gpio24 .

I'm trying on a Raspberry Pi 3 with the following code: https://github.com/fmatosqg/androidthings_ndk/tree/SO_question

In another approach I tried loading libperipheralman.so directly in java in the hopes of making calls to its functions (apparently that's where GPIO setValue() lives), but this time I ran into a different kind of problem where a subset of the libraries were denied being loaded by some security problem. See Nougat documentation about them not allowing developers to access all .so because of back/future compatibility purposes.

I guess that any implementation that skips using Java VM/Dalvik has also the potential of gettting me closer to my goal, which is getting decent GPIO speed on an .apk, but I'm unaware if any of the approaches that work on rpi3 + debian can be used here.

EDITED:

Run something like this everytime you're about to run the app (works for pin 24, replace with your preferred pin):

cd /sys/class/gpio
su root chmod a+w export
echo 24 > export
su root chmod a+w gpio24/direction
su root chmod a+w gpio24/value

ls gpio24/ -l

Unfortunately calling execl returns -1 and system returns 32256, so there's no way to replace this manual step. Even by trying system("/system/bin/date > /storage/self/primary/now "); will give 32256.

Then put together a script that listens to a named pipe and based on that runs the above code. After struggling a bit with su and chmod to make it easy to run I put together a C code that would write to that same pipe. Add 300ms wait for the pipe to be read and I'd start writing to gpio23/direction and gpio/value from C code from inside apk.

Led is getting lit, and as soon as I optimize the C code for a tighter loop I'll post some speed benchmarking.

Full solution here https://github.com/fmatosqg/androidthings_ndk/tree/SO_answer . Have a look at README.md for instructions.

To make it better I'd need to debug the named pipe reading because sometimes I read the wrong info. And also make the script start at boot.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM