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

droidconfr2013-discover-embedded-linux-with-android

 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)

C2d7e750b1cc7dd5a74bd6aca1b49941?s=128

Cédric Cabessa

June 17, 2013
Tweet

Transcript

  1. Discover embedded Linux with Android Cédric Cabessa ccabessa@genymobile.com

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

    multimedia content and consumer. Money is made selling games, music and so on.
  3. 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
  4. Introduction Can we keep Android with it's UI, its fully

    integrated API and yet use it to build our own embedded system ?
  5. Introduction Android IS Linux

  6. 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
  7. 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).
  8. Case study • Let's play with hardware !

  9. 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
  10. 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
  11. 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.
  12. 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
  13. 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
  14. 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
  15. HAL We simply load the driver and check permission. It's

    time to use it. Hardware Abstraction Layer
  16. 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)
  17. 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
  18. JNI Hal is C, System Service is java => jni

  19. 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.
  20. 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); }
  21. 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
  22. 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.
  23. 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.
  24. System Service • frameworks/base/services/java/com/android/server/ DroidconService.java

  25. 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)
  26. 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); }
  27. Framework DroidconService is launched at startup. It listen to a

    Binder interface. We have to write the client side: Framework
  28. 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)
  29. 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); }});
  30. Framework • Create a new SDK ◦ make update-api ◦

    make sdk • Configure eclipse
  31. Framework <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.droidcon" android:versionCode="1" android:versionName="1.0" >

    <uses-permission android:name="android.permission.DROIDCON_ACCESS"/> • AndroidManifest.xml
  32. Framework

  33. Framework

  34. Framework

  35. 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?
  36. References • Remixing Android http://marakana.com/s/post/1044/remixing_android • Adding System Service http://processors.wiki.ti.com/index.php/Android-

    Adding_SystemService
  37. Q&A Genymobile SAS - 41, rue Meslay 75003 PARIS -

    01 83 64 25 40 www.genymobile.com QUESTIONS ? Cédric Cabessa ccabessa@genymobile.com https://speakerdeck.com/cedriccabessa/ droidconfr2013-discover-embedded-linux-with-android https://github.com/CedricCabessa/droidconfr2013
  38. Discover embedded Linux with Android Cédric Cabessa ccabessa@genymobile.com

  39. Introduction

  40. Introduction

  41. Introduction

  42. Introduction

  43. The Question • How to modify Android to support a

    new hardware / new features without asking Google. • Android Style
  44. Case study • http://source.android.com • Nexus • Pandaboard • Manufacturer

    support
  45. Case study • Let's play with hardware !

  46. Case study • Character device: /dev/droidcon • Convert upper case

    to lower case, in kernel land!
  47. Case study

  48. Kernel / Driver • Not part of AOSP • Driver

    can be built with the kernel • Or as a seperate module (.ko) • GPLv2
  49. 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
  50. 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 #
  51. 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
  52. HAL

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

    hardware feature • Often closed source :-(
  54. 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
  55. JNI

  56. 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"); } }
  57. 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); }
  58. 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
  59. System Service

  60. 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); }
  61. System Service • frameworks/base/services/java/com/android/server/ DroidconService.java

  62. 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"); }
  63. 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); }
  64. Framework

  65. 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; }
  66. 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); }});
  67. Framework • Create a new SDK ◦ make update-api ◦

    make sdk • Configure eclipse
  68. Framework <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.droidcon" android:versionCode="1" android:versionName="1.0" >

    <uses-permission android:name="android.permission.DROIDCON_ACCESS"/> • AndroidManifest.xml
  69. Framework

  70. Framework

  71. Framework

  72. 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?
  73. References • Remixing Android http://marakana.com/s/post/1044/remixing_android • Adding System Service http://processors.wiki.ti.com/index.php/Android-

    Adding_SystemService
  74. Q&A Genymobile SAS - 41, rue Meslay 75003 PARIS -

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