Extending Android with New Devices

Preview:

DESCRIPTION

Shows how a device maker can extend Android to support new devices, while preserving Android compatibility. We demonstrate a joystick & an industrial barcode scanner.

Citation preview

Extending Android with New Devices

Shree Kumar InnoMinds Software

Nitheesh K L PES Institute of Technology

Android outside the mobile context

Speaker Intro

Shree Kumar InnoMinds Software

Nitheesh K L PES Institute of Technology

Background • Android expected to proliferate

– Not just on smart-phones & tablets • Android built with MID devices in mind

– Newer use cases => other devices – Changing the API is not permitted

• New devices, Additional APIs !

Extending Android with New Devices | DroidCon India 2011

Overview • Device support in Linux • Layered approach for Android • Two examples

– Joystick – Industrial Barcode Scanner

• Device Maker’s Perspective – Standardized interfaces may not happen due to

schedules – Market compatibility provided

Extending Android with New Devices | DroidCon India 2011

Linux Device Support

User App Device API

Privileged Daemon

udev Device Node

Kernel

Device SUBSYSTEMS="usb",ATTRS(idVendor)=="0bb4",MODE="0666",OWNER="shree" SUBSYSTEMS="usb",ATTRS(idVendor)=="8086",MODE="0666",OWNER="shree"

Linux devs : Remember adding these lines to /etc/udev/rules.d/51-android.rules?

setuid() setgid()

Extending Android with New Devices | DroidCon India 2011

Our Android Approach

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel

Device

Platform Library Preserves Android

Compatibility

chown USER:GROUP /dev/XYZ chmod 0ppp /dev/XYZ

mknod /dev/XYZ

sharedUserId=android.uid.system

Extending Android with New Devices | DroidCon India 2011

uses-permission=USE_DEVICE uses-library=sample_device

Example 1 • Supporting a USB Joystick • Why this device ?

– Simplicity – Map concepts to details

• You need – Android device with USB host/OTG

Extending Android with New Devices | DroidCon India 2011

Joystick : Step 1 • Kernel drivers

– Defaults to HID raw driver present – Boot & Check

• Device node – /dev/input/eventX

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Device

Kernel

$ cat /proc/bus/input/devices | grep ^[NH] | grep –A 1 Gamepad \ > | grep event N: Logitech Precision Gamepad H: Handlers=event15

Joystick : Step 2

• Interface to the device node

– Read /dev/input/eventX • Get single key code per event

– ev.code : scan code – ev.value : key down/up

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

fd = open(“/dev/input/event15”, O_RDONLY);

struct input_event ev;

rd = read (fd, &ev, sizeof(struct input_event);

Joystick : Step 2 (contd) • Wrap native code using JNI

• Android.mk – generate lib

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

static const JNINativeMethod gMethods[] = {

{“open”, “()Z”, (void *)Java_Joystick_open},

{“getKey”, “()I”, (void *)Java_Joystick_getKey},

{“close”, “()V”, (void *)Java_Joystick_close},

};

Jint JNI_OnLoad(JavaVM* vm, void* reserved) {

//register your methods

...

}

LOCAL_MODULE := libsample_joystick

Joystick : Step 3 • Permission for device node

– <Android-src>/system/core/init/devices.c

– Ueventd.rc

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

Static struct perms_devperms[] = {

...

{“/dev/input”, 0666, AID_SYSTEM, AID_INPUT, 1},

...

}

$ls –l /dev/input

crw-rw---- system input 13, 79 2011-11-18 14:05 event15

crw-rw---- system input 13, 79 2011-11-18 14:05 event11

crw-rw---- system input 13, 79 2011-11-18 14:05 event4

...

Joystick : Step 4 • Service Wrapper around JNI

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

|

+---com

| \---sample

| +---hardware

| | \---joystick

| | JoystickAPI.aidl

| | JoystickCallback.aidl

| | Joystick.java

| | Joystick.class

| |

| \---service

| JoystickService.java

|

+---jni

| Android.mk

| Joystick.h

| Joystick.cpp

| Jsfunctions.h

| Jsfunctions.cpp

Joystick : Step 4 (contd) • Signed APK provides privileged access

• Define permission in AndroidManifest.xml

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

# we ask for restricted permissions for our service,

# so the apk has to be signed

LOCAL_CERTIFICATE := platform

<permission android:name = “com.sample.USE_JOYSTICK” />

Joystick : Step 4 (contd)

• IPC service exposes API to applications – …/ JoystickAPI.aidl

– … / JoystickService.java

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

interface JoystickAPI {

boolean setCallback(in JoystickCallback cb);

boolean clearCallback();

}

Private JoystickAPI.Stub api = new JoystickAPI.Stub(){

public boolean setCallback(JoystickCallback cb){

// enable setting callback

}

public boolean clearCallback(){

// enable clearing callback

}

}

Joystick : Step 5

• Platform Library • Declare your library to the framework

– /system/etc/permissions – com.sample.hardware.joystick.xml

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

<?xml version="1.0" encoding="utf-8"?>

<permissions>

<library name="com.sample.hardware.joystick"

file="/system/framework/com.sample.hardware.joystick.jar"/>

</permissions>

adb push \

out/target/product/generic_x86/system/framework/com.sample.hardware.joystick.jar \

/system/framework

• Output product is raw .jar file, NOT a .apk

Joystick : Step 6 • Application interacts with device

– Binds to Service – Uses API provided by Service

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

Intent intent = new Intent(“com.sample.android.service.JoystickService”);

bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);

ServiceConnection sc = new ServiceConnection(){

private void onServiceConnected(ComponentName n, Ibinder service){

api = Ijoystick.stub.asInterface(service);

try{

api.setCallback(jsCallback);

}catch (RemoteException e){

}

}

}

Joystick : Step 6 (contd) • Run on UI Thread

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

JoystickCallback jsCallback = new JoystickCallback.Stub() {

private void onKeyPress(int arg0) throws RemoteException {

final int key = arg0;

runOnUiThread(new Runnable(){

public void run(){

updateUI(key);

}

});

}

};

Joystick : Step 6 (contd) User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

Joystick : Overall User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

Example 2 • Barcode Scanner

– Opticon MDI 2300 • 2D scanner

– Available as a module for development

Extending Android with New Devices | DroidCon India 2011

Example 2 • Why use a dedicated device ?

– Supports tons of symbologies – Purpose made

• Fast • Long cables, Laser illumination

– Would you drop your smart-phone ?

ZXing symbology support

Opticon symbology support, “Menubook” excerpt

Extending Android with New Devices | DroidCon India 2011

Barcode Scanner : Step 1 • Setup the device

– We’ll use USB VCP (Virtual COM Port) mode – Scan barcodes! Barcodes vary by device.

USB VCP configuration for MDI 2300 | Screenshot from opticonfigure.opticon.com

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

Excerpts from Sec 2-5 of Xenon 1900 User Guide

Extending Android with New Devices | DroidCon India 2011

Barcode Scanner : Step 2 • Change the kernel

– Specific steps depend on Android/kernel version – Include support for CDC ACM devices

• Ensure support for protocol=“None” in cdc-acm.c

• Boot with the new kernel & check

/* control interfaces without any protocol set */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_PROTO_NONE) },

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

Extending Android with New Devices | DroidCon India 2011

Barcode Scanner : Step 3 • Interface to the driver

– Read /dev/ttyACM0 – Get single barcode per line

• Test… at every step • Wrap native code using JNI

– Can an app use the wrapper ?

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

# ls –l /dev/input* crw-r----- 1 system input 13, 64 2011-11-02 14:51 event0 crw-r----- 1 system input 13, 64 2011-11-02 14:51 event1

Extending Android with New Devices | DroidCon India 2011

Barcode Scanner : Step 4 • ueventd : fix /dev/ttyACM0 access

– owner “system” (android.uid.system)

– Another method: owner “com.sample.uid.acm” • Passes Android Compatibility !

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

mSettings.addSharedUserLP("android.uid.system", Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM); … mSettings.addSharedUserLP("com.sample.uid.acm", 1018, ApplicationInfo.FLAG_SYSTEM);

frameworks/base/services/java/com/android/server/PackageManagerService.java

/dev/ttyACM0 0660 system root

Add this line to : system/core/rootdir/ueventd.rc

Extending Android with New Devices | DroidCon India 2011

Barcode Scanner : Step 5 • Service Wrapper around JNI

– AIDL based IPC service exposes API to applications

– Signed APK provides privileged access

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

interface IBarcodeScanner { boolean setCallback(in BarcodeScannerCallback callback); boolean scanBarcode(int timeout); boolean clearCallback(); }; Interface BarcodeScannerCallback { void handlerBarcode(boolean timedout, String barcode); }

android:sharedUsedId=“android.uid.system”

Extending Android with New Devices | DroidCon India 2011

Barcode Scanner : Step 6 • Application interacts with device

– Binds to Service – Uses API provided by Service

• Could be beautified… – Unbinds when done!

User App (Java) Service Wrapper (optional)

Privileged Service (Java)

ueventd

JNI Interface

Device Node

Kernel Device

Extending Android with New Devices | DroidCon India 2011

Summary • HOWTO-support-devices-on-android.txt

– Important steps – Examples

• Kept simple on purpose – Skipped

• Power Management • Deeper system integration

– You may want to rethink the interfaces !

Extending Android with New Devices | DroidCon India 2011

Questions ?

Shree shree.shree@gmail.com

Nitheesh nitheeshkl@gmail.com

Recommended