Upgrade to Pro — share decks privately, control downloads, hide ads and more …

droidconfr2013-discover-embedded-linux-with-and...

 droidconfr2013-discover-embedded-linux-with-android

Talk given at droidcon fr 2013
http://fr.droidcon.com/2013/sessions/genymobile/

Code sample are available:
https://github.com/CedricCabessa/droidconfr2013

Video:
http://www.youtube.com/watch?v=BgP-QjjWCfA

slide 1 to 37 have speaker notes
slide 38 to the end are the same without speaker notes (download pdf to have correct ratio, speakerdeck do not support slide rotation)

Cédric Cabessa

June 17, 2013
Tweet

More Decks by Cédric Cabessa

Other Decks in Programming

Transcript

  1. Introduction Android is for mass market. Ecosystem is oriented toward

    multimedia content and consumer. Money is made selling games, music and so on.
  2. Introduction On the other hand, embedded linux is used to

    create everykind of project, you have drivers for everything, you can plug any devices you want. The "hdtv blueray microwave washing machine" come from the Yocto-project
  3. Introduction Can we keep Android with it's UI, its fully

    integrated API and yet use it to build our own embedded system ?
  4. The Question • How to modify Android to support a

    new hardware / new features without asking Google. • Android Style You have a dev board (like a pandaboard) with Android. You want to plug a new device (gpio, i2c, rs232, ...). How to use it with an Android like API
  5. Case study • http://source.android.com • Nexus • Pandaboard • Manufacturer

    support Android is opensource (AOSP), it is fairly easy to grab the source and build your own ROM (if you have hardware support: nexus or dev board with manufacturer support).
  6. Case study • Character device: /dev/droidcon • Convert upper case

    to lower case, in kernel land! In linux, most of the drivers are exposed through the "/dev" fiilesystem. To send data to the driver, you simply open the file and write to it. In real life, we assume you already have a driver for your device
  7. Case study We assume we have a support for linux

    (driver) for our new hardware, we want to create applications that use it. We have to patch every layer from kernel to framework
  8. Kernel / Driver • Not part of AOSP • Driver

    can be built with the kernel • Or as a seperate module (.ko) • GPLv2 Driver is provided by your board manufacturer (kernel) or as a module from your device provider. Of course you can write your own if you have a custom device.
  9. Kernel / Driver • init.rc on boot insmod /system/lib/modules/droidcon.ko chown

    system system /dev/droidcon chmod 0600 /dev/droidcon • device/<vendor>/<product>/device.mk PRODUCT_COPY_FILES := \ device/<vendor>/<product>/droidcon.ko:system/lib/modules/droidcon.ko
  10. Kernel / Driver • Try it (connect as root) adb

    shell # ls -l /dev/droidcon crw------- system system 249, 0 droidcon # echo Hello > /dev/droidcon # cat /dev/droidcon hELLO # with real world devices, it is hard to check everything works just after loading the module
  11. Kernel / Driver • Our device is only usable by

    'system' • Run our app as system? => NO • system_server use the device • App communicate with system_server We will have to create permissions
  12. HAL We simply load the driver and check permission. It's

    time to use it. Hardware Abstraction Layer
  13. HAL • C library • Talk to driver • Expose

    hardware feature • Often closed source :-( expose hardware feature: driver can only support read / write, HAL should expose more advanced semantics that are implemented using read/write/... ex: usb missile launcher: HAL: missile_launch() Driver: write(/dev/foo, 42)
  14. HAL • hardware/droidcon/lib • libdroidcon.h ssize_t droidcon_getdata(void *buf, size_t count);

    ssize_t droidcon_putdata(const void *buf, size_t count); void droidcon_clear(void); • Do complicated thing here! And only here The driver only support open / read / write / close. We create a "droidcon_clear" function, this semantic make sense from a driver user point of view. In fact it is implemented as write(fd, 0, 0) ==> intelligent stuff go here
  15. JNI • frameworks/base/core/java/android/droidcon/ LibDroidcon.java package android.droidcon; public class LibDroidcon {

    public native static void clear(); public native static String getData() throws DroidconException; public native static void putData(String in) throws DroidconException; static { System.loadLibrary("droidcon_jni"); } } Rem: we hack framework! May be we could separate our change from the standard android, but we will have to modify SystemServer so can't stay really separated.
  16. JNI • hardware/droidcon/jni/ android_droidcon_LibDroidcon.c JNIEXPORT void JNICALL Java_android_droidcon_LibDroidcon_putData (JNIEnv *env,

    jclass cls, jstring string) { int ret; const char *buff = (*env)->GetStringUTFChars(env, string, NULL); int length = (*env)->GetStringLength(env, string); ret = droidcon_putdata(buff, length); if (ret < 0) { ThrowDroidconException(env, "fail to put data"); } (*env)->ReleaseStringUTFChars(env, string, buff); }
  17. JNI • Tip for testing: ◦ Add a Main.java in

    android.droidcon public class Main { public static void main (String[] args) { try { LibDroidcon.putData("Hello"); String out = LibDroidcon.getData(); System.out.println(out); LibDroidcon.clear(); } catch (DroidconException e) { Log.d("droidcon", e.toString()); } } } ◦ Run it with the shell # dalvikvm android.droidcon.Main hELLO
  18. System Service Now we can use our HAL from java.

    SystemService run as system. When you use context.getSystemService(...) you only get a proxy that send command through binder IPC to the SystemService. System Service do the real work and check permission.
  19. System Service • Must implement a Binder interface • framework/base/droidcon/java/android/droidcon/

    IDroidconManager.aidl package android.droidcon; /** {@hide} */ interface IDroidconManager { void clear(); String getData(); void putData(String data); } Declare every methods the client (framework) can call on the server (System Service) Can't throw exception here. Use return code or something else.
  20. System Service package com.android.server; /** @hide */ class DroidconService extends

    IDroidconManager.Stub { public String getData() { enforceAccessPermission(); try { return LibDroidcon.getData(); } catch(DroidconException e) { Slog.d(TAG, "cannot getdata"); } return null; } private void enforceAccessPermission() { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DROIDCON_ACCESS, "DroidconService"); } IDroidconManager.Stub is automatically generated from IDroidconManager.aidl Check for exception here and return Enforce permission (framework/base/core/res/AndroidManifest.xml)
  21. System Service • Hack SystemServer.java public void run() { [...]

    try { Slog.i(TAG, "Droidcon Service"); droidconService = new DroidconService(context); ServiceManager.addService(Context.DROIDCON_SERVICE, droidconService); } catch (Throwable e) { reportWtf("starting Droidcon Service", e); }
  22. Framework DroidconService is launched at startup. It listen to a

    Binder interface. We have to write the client side: Framework
  23. Framework • framework/base/droidcon/java/android/droidcon DroidconManager.java public class DroidconManager { IDroidconManager mService;

    /** @hide */ public DroidconManager(IDroidconManager service) { mService = service; } public String getData() { try { return mService.getData(); } catch (RemoteException e) { e.printStackTrace(); } return null; } Do nothing but calling methods through the binder interface (and checking return value)
  24. Framework • Hack ContextImpl.java class ContextImpl extends Context { static

    { [...] registerService(DROIDCON_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(DROIDCON_SERVICE); IDroidconManager service = IDroidconManager.Stub.asInterface (b); return new DroidconManager(service); }});
  25. Conclusion • Hardware support is not an excuse to not

    choose Android • Kernel Driver and HAL should be re-usable • Upper layers are mostly "glue code" • Fragmentation?
  26. Q&A Genymobile SAS - 41, rue Meslay 75003 PARIS -

    01 83 64 25 40 www.genymobile.com QUESTIONS ? Cédric Cabessa [email protected] https://speakerdeck.com/cedriccabessa/ droidconfr2013-discover-embedded-linux-with-android https://github.com/CedricCabessa/droidconfr2013
  27. The Question • How to modify Android to support a

    new hardware / new features without asking Google. • Android Style
  28. Kernel / Driver • Not part of AOSP • Driver

    can be built with the kernel • Or as a seperate module (.ko) • GPLv2
  29. Kernel / Driver • init.rc on boot insmod /system/lib/modules/droidcon.ko chown

    system system /dev/droidcon chmod 0600 /dev/droidcon • device/<vendor>/<product>/device.mk PRODUCT_COPY_FILES := \ device/<vendor>/<product>/droidcon.ko:system/lib/modules/droidcon.ko
  30. Kernel / Driver • Try it (connect as root) adb

    shell # ls -l /dev/droidcon crw------- system system 249, 0 droidcon # echo Hello > /dev/droidcon # cat /dev/droidcon hELLO #
  31. Kernel / Driver • Our device is only usable by

    'system' • Run our app as system? => NO • system_server use the device • App communicate with system_server
  32. HAL

  33. HAL • C library • Talk to driver • Expose

    hardware feature • Often closed source :-(
  34. HAL • hardware/droidcon/lib • libdroidcon.h ssize_t droidcon_getdata(void *buf, size_t count);

    ssize_t droidcon_putdata(const void *buf, size_t count); void droidcon_clear(void); • Do complicated thing here! And only here
  35. JNI

  36. JNI • frameworks/base/core/java/android/droidcon/ LibDroidcon.java package android.droidcon; public class LibDroidcon {

    public native static void clear(); public native static String getData() throws DroidconException; public native static void putData(String in) throws DroidconException; static { System.loadLibrary("droidcon_jni"); } }
  37. JNI • hardware/droidcon/jni/ android_droidcon_LibDroidcon.c JNIEXPORT void JNICALL Java_android_droidcon_LibDroidcon_putData (JNIEnv *env,

    jclass cls, jstring string) { int ret; const char *buff = (*env)->GetStringUTFChars(env, string, NULL); int length = (*env)->GetStringLength(env, string); ret = droidcon_putdata(buff, length); if (ret < 0) { ThrowDroidconException(env, "fail to put data"); } (*env)->ReleaseStringUTFChars(env, string, buff); }
  38. JNI • Tip for testing: ◦ Add a Main.java in

    android.droidcon public class Main { public static void main (String[] args) { try { LibDroidcon.putData("Hello"); String out = LibDroidcon.getData(); System.out.println(out); LibDroidcon.clear(); } catch (DroidconException e) { Log.d("droidcon", e.toString()); } } } ◦ Run it with the shell # dalvikvm android.droidcon.Main hELLO
  39. System Service • Must implement a Binder interface • framework/base/droidcon/java/android/droidcon/

    IDroidconManager.aidl package android.droidcon; /** {@hide} */ interface IDroidconManager { void clear(); String getData(); void putData(String data); }
  40. System Service package com.android.server; /** @hide */ class DroidconService extends

    IDroidconManager.Stub { public String getData() { enforceAccessPermission(); try { return LibDroidcon.getData(); } catch(DroidconException e) { Slog.d(TAG, "cannot getdata"); } return null; } private void enforceAccessPermission() { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DROIDCON_ACCESS, "DroidconService"); }
  41. System Service • Hack SystemServer.java public void run() { [...]

    try { Slog.i(TAG, "Droidcon Service"); droidconService = new DroidconService(context); ServiceManager.addService(Context.DROIDCON_SERVICE, droidconService); } catch (Throwable e) { reportWtf("starting Droidcon Service", e); }
  42. Framework • framework/base/droidcon/java/android/droidcon DroidconManager.java public class DroidconManager { IDroidconManager mService;

    /** @hide */ public DroidconManager(IDroidconManager service) { mService = service; } public String getData() { try { return mService.getData(); } catch (RemoteException e) { e.printStackTrace(); } return null; }
  43. Framework • Hack ContextImpl.java class ContextImpl extends Context { static

    { [...] registerService(DROIDCON_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(DROIDCON_SERVICE); IDroidconManager service = IDroidconManager.Stub.asInterface (b); return new DroidconManager(service); }});
  44. Conclusion • Hardware support is not an excuse to not

    choose Android • Kernel Driver and HAL should be re-usable • Upper layers are mostly "glue code" • Fragmentation?
  45. Q&A Genymobile SAS - 41, rue Meslay 75003 PARIS -

    01 83 64 25 40 www.genymobile.com QUESTIONS ? Cédric Cabessa [email protected] https://speakerdeck.com/cedriccabessa/ droidconfr2013-discover-embedded-linux-with-android https://github.com/CedricCabessa/droidconfr2013