Android is a great OS for many devices and not mobile only. You can even use Android on devices without display (headless). The most important thing about Android is the fact that it is open source and you can build everything from source.

Android structure:

The lower layer is Linux kernel with some changes (little)

The Native Layer is built above the kernel and hosts the C library, other system libraries, and many daemons

The Application Framework layer hosts all the Android services used by Android Applications

In this post, we will build a Native Daemon in the native layer, make it run on system startup and using system property and build application to communicate with our daemon.

Create a directory in device/generic/goldfish/bin/mylogger

Add mylogger.c

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { int fd=open("/data/data1",O_RDWR|O_CREAT,0660); char buffer[100]; struct sockaddr_in addr = {0}; size_t addrlen, n; int sockfd = socket(AF_INET, SOCK_DGRAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(2000); addr.sin_addr.s_addr = INADDR_ANY; bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)); addrlen = sizeof(addr); while(1) { n = recvfrom(sockfd, (void*)buffer, 100, 0, (struct sockaddr*)&addr, (unsigned int *) &addrlen); buffer[n] = '

'; write(fd,buffer,n+1); } close(fd); return 0; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main ( ) { int fd = open ( "/data/data1" , O_RDWR | O_CREAT , 0660 ) ; char buffer [ 100 ] ; struct sockaddr_in addr = { 0 } ; size_t addrlen , n ; int sockfd = socket ( AF_INET , SOCK_DGRAM , 0 ) ; addr . sin_family = AF_INET ; addr . sin_port = htons ( 2000 ) ; addr . sin_addr . s_addr = INADDR_ANY ; bind ( sockfd , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ; addrlen = sizeof ( addr ) ; while ( 1 ) { n = recvfrom ( sockfd , ( void * ) buffer , 100 , 0 , ( struct sockaddr * ) & addr , ( unsigned int * ) & addrlen ) ; buffer [ n ] = '

' ; write ( fd , buffer , n + 1 ) ; } close ( fd ) ; return 0 ; }

Add Android.mk file

LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:=\ mylogger.c LOCAL_CFLAGS:=-O2 -g #LOCAL_CFLAGS+=-DLINUX LOCAL_MODULE_TAGS := eng LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_MODULE:=mylogger # gold in binutils 2.22 will warn about the usage of mktemp LOCAL_LDFLAGS += -Wl,--no-fatal-warnings include $(BUILD_EXECUTABLE) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 LOCAL_PATH : = $ ( call my - dir ) include $ ( CLEAR_VARS ) LOCAL_SRC_FILES : = \ mylogger . c LOCAL_CFLAGS : = - O2 - g #LOCAL_CFLAGS+=-DLINUX LOCAL_MODULE_TAGS : = eng LOCAL_MODULE_PATH : = $ ( TARGET_OUT_OPTIONAL_EXECUTABLES ) LOCAL_MODULE : = mylogger # gold in binutils 2.22 will warn about the usage of mktemp LOCAL_LDFLAGS += - Wl , -- no - fatal - warnings include $ ( BUILD_EXECUTABLE )

If we add the service definition to init.rc file without a security label we will get:

service mylogger does not have a SELinux domain defined

So we define the security label for it:

on property:myprop.test=1 start mylogger on property:myprop.test=0 stop mylogger service mylogger /system/xbin/mylogger user root group root seclabel u:r:su:s0 1 2 3 4 5 6 7 8 9 10 on property : myprop . test = 1 start mylogger on property : myprop . test = 0 stop mylogger service mylogger / system / xbin / mylogger user root group root seclabel u : r : su : s0

We need to define the system property for SE Android. Add the following line to property_contexts file:

myprop.test u:object_r:system_prop:s0 1 myprop . test u : object_r : system_prop : s0

Writing Client Application

We can write a client application using Android Studio. Simply add a button and write a click handler, use a thread to send a UDP message to the daemon:

public class MainActivity extends AppCompatActivity { void sendonemsg() { DatagramSocket s; try { s = new DatagramSocket(); InetAddress local = InetAddress.getByName("127.0.0.1"); String str="hello service"; int msg_length = str.length(); DatagramPacket p = new DatagramPacket(str.getBytes(), msg_length, local, 2000); s.send(p); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button b=(Button)findViewById(R.id.button); b.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Thread t=new Thread(new Runnable(){ @Override public void run() { sendonemsg();; } }); t.start(); } }); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class MainActivity extends AppCompatActivity { void sendonemsg ( ) { DatagramSocket s ; try { s = new DatagramSocket ( ) ; InetAddress local = InetAddress . getByName ( "127.0.0.1" ) ; String str = "hello service" ; int msg_length = str . length ( ) ; DatagramPacket p = new DatagramPacket ( str . getBytes ( ) , msg_length , local , 2000 ) ; s . send ( p ) ; } catch ( Exception e ) { // TODO Auto-generated catch block e . printStackTrace ( ) ; } } @Override protected void onCreate ( Bundle savedInstanceState ) { super . onCreate ( savedInstanceState ) ; setContentView ( R . layout . activity_main ) ; Button b = ( Button ) findViewById ( R . id . button ) ; b . setOnClickListener ( new View . OnClickListener ( ) { @Override public void onClick ( View view ) { Thread t = new Thread ( new Runnable ( ) { @Override public void run ( ) { sendonemsg ( ) ; ; } } ) ; t . start ( ) ; } } ) ; }

Add INTERNET permission request to AndroidManifest.xml file

To set the system property we need to write a system application with C++ code:

static void setService(JNIEnv *env, jclass clazz, jboolean s) { if(s) property_set("myprop.test", "1"); else property_set("myprop.test", "0"); } 1 2 3 4 5 6 7 static void setService ( JNIEnv * env , jclass clazz , jboolean s ) { if ( s ) property_set ( "myprop.test" , "1" ) ; else property_set ( "myprop.test" , "0" ) ; }

To use property_set function you need to add libcutils to Android.mk:

LOCAL_SHARED_LIBRARIES := \ libutils liblog libcutils 1 2 LOCAL_SHARED_LIBRARIES : = \ libutils liblog libcutils

The last thing to do is add an allow rule to system_app to set the property:

Add the following rule to system_app.te

allow system_app system_prop:property_service { set }; 1 allow system_app system_prop : property_service { set } ;

Now setting the system property is triggering start and stop and using the client application we can send messages to the daemon. To see the result cat the file data1: