FlexCAN support in Android: How to invoke a system command in application code?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

FlexCAN support in Android: How to invoke a system command in application code?

Jump to solution
4,153 Views
kaancetinkaya
Contributor II

Hi,

I have SABRE-AI development board and I've installed Android operating system on it. I am developing an Android application which will interface with CAN bus through FlexCAN support on Kernel. As mentioned here, How to use FlexCAN in Android, Android BSP provided by Freescale comes with FlexCAN support in kernel space with SocketCAN drivers. SocketCAN extends the classical Berkeley sockets API by introducing a new protocol family for interfacing CAN networks. Therefore, starting/stopping or configuring an existing CAN interface can be realized by using 'iproute2' utilities on command line. After that it is possible to use FlexCAN in Android by using the classical socket programming techniques in application code. However, I also want to configure and start an existing CAN interface in my application code. The only solution I've come up is that I can invoke those system commands in my application code. But it requires root access and I couldn't manage how to do it.

For example;

Following command should be run in command line in order to start can0 interface with 125kbit rate. And, it perfectly works if I run it manually in a shell window.

ip link set can0 up type can bitrate 125000

I am running following code in my application to do same thing;

Process p = Runtime.getRuntime().exec("ip link set can0 up type can bitrate 125000");

But process p gives an error that "RTNetlink answers: Operation not permitted." I have also tried to execute it under "su" process but it didn't work. Signing the application with platform keys also didn't resolve my issue. Do you have any ideas how to invoke a system command in application code for Android?

Btw, I rebuilt the linux-can-utils binaries for Android using the Android native development kit and imported them to my SABRE-AI board. I can successfully send and receive CAN messages by invoking those binaries in my application code once I configure and start the interface manually on a shell window before running my application.

Labels (2)
1 Solution
2,272 Views
kaancetinkaya
Contributor II

I have solved the issue myself. Android should be rooted in order to be able to invoke such system commands requiring root access. I've mistaken such a simple point. If anyone needs it, I'm explaining what I've done;

1. Android should be rooted by using some 3rd party application. Google for how to do it.

2. After rooting Android, it is possible to execute "su" process in normal-user level. In application code, create and execute a "su" process in which our commands will be executed with root permissions:

...

Process suProcess = Runtime.getRuntime().exec("su");

3. Input your commands to that process by using  DataOutputStream class;

...

DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());

os.writeBytes("command-string-to-be-executed");

os.flush();

4. End the process;

...

os.writeBytes("exit\n");

os.flush();

This is what happens in summary; our application will start a seperate process with root permissions, it executes the commands in that process, finally it ends the process.

I think this is the easiest way of controlling, i.e, configuring/starting/stopping, FlexCAN interface in application code. Then you can develop your own user space methods to send and receive CAN messages using classical Socket-API. Or, you can use an existing one such as Rick suggested. Here is my implementation with proper error handling included;

A generic class that can be used to execute system commands with root permissions;

public class ExecuteAsRoot

{

   public ArrayList<String> commands;

   public ExecuteAsRoot(ArrayList<String> arr) {

      commands = new ArrayList<String>();

      for (int i=0; i<arr.size(); i++)

           commands.add(arr.get(i));

   }

   public boolean execute() {

       boolean retVal = false;  

       try {

          if (null != commands && commands.size() > 0) {         

             Process suProcess = Runtime.getRuntime().exec("su");

             DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());

             for (String currCommand : commands) {

                os.writeBytes(currCommand + "\n");

                os.flush();

             }

             os.writeBytes("exit\n");

             os.flush();

             BufferedReader stderr = new BufferedReader(new InputStreamReader(suProcess.getErrorStream()));

             String line = "";

             String errString = "";

             while ((line = stderr.readLine()) != null) errString += line + "\n";

             suProcess.waitFor();

             if (suProcess.exitValue() != 0)

                throw new Exception(errString);

            retVal = true;

         }

     } catch (Exception e) {

         retVal = false;

         Log.d("ERR", e.getMessage());

         e.printStackTrace();

     }     

  return retVal;

  }

}

A part of application code to control FlexCAN interface;

// ....

public boolean createVirtualCANInterface(String interfaceName) {

  ArrayList<String> commands = new ArrayList<String>();

  commands.add("ip link add dev " + interfaceName + " type vcan");

  ExecuteAsRoot p = new ExecuteAsRoot(commands);

  return p.execute();

}

public boolean setBitRate(String interfaceName, long bitrate) {

  ArrayList<String> commands = new ArrayList<String>();

  commands.add("ip link set " + interfaceName + " type can bitrate " + bitrate);

  ExecuteAsRoot p = new ExecuteAsRoot(commands);

  return p.execute();

}

public boolean startDevice(String interfaceName) {

  ArrayList<String> commands = new ArrayList<String>();

  commands.add("ip link set " + interfaceName + " up");

  ExecuteAsRoot p = new ExecuteAsRoot(commands);

  return p.execute();

}

public boolean stopDevice(String interfaceName) {

  ArrayList<String> commands = new ArrayList<String>();

  commands.add("ip link set " + interfaceName + " down");

  ExecuteAsRoot p = new ExecuteAsRoot(commands);

  return p.execute();

}

// ...

View solution in original post

0 Kudos
7 Replies
2,271 Views
djmodel
Contributor I

If you using android5.0 above version system,you do‘t need ‘su’ to access flexcan.The problem is that SELinux allows access to the rules of error, close SELinux can be normal execution.

0 Kudos
2,271 Views
sachusanal
Contributor III

Dear Kaan ,

I am new to this Android building environment. I downloaded the android lolipop package  from the freescale . And start android build . i  download the kernel source code. let me know how can configure the kernel for CAN means which command is using .

how can test the CAN  functionality in android OS . do you have any java code to test the functionality. or otherwise how can build the can utlities for user space.

please help me

Awaiting your favorable reply

Regards

Sachu

2,273 Views
kaancetinkaya
Contributor II

I have solved the issue myself. Android should be rooted in order to be able to invoke such system commands requiring root access. I've mistaken such a simple point. If anyone needs it, I'm explaining what I've done;

1. Android should be rooted by using some 3rd party application. Google for how to do it.

2. After rooting Android, it is possible to execute "su" process in normal-user level. In application code, create and execute a "su" process in which our commands will be executed with root permissions:

...

Process suProcess = Runtime.getRuntime().exec("su");

3. Input your commands to that process by using  DataOutputStream class;

...

DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());

os.writeBytes("command-string-to-be-executed");

os.flush();

4. End the process;

...

os.writeBytes("exit\n");

os.flush();

This is what happens in summary; our application will start a seperate process with root permissions, it executes the commands in that process, finally it ends the process.

I think this is the easiest way of controlling, i.e, configuring/starting/stopping, FlexCAN interface in application code. Then you can develop your own user space methods to send and receive CAN messages using classical Socket-API. Or, you can use an existing one such as Rick suggested. Here is my implementation with proper error handling included;

A generic class that can be used to execute system commands with root permissions;

public class ExecuteAsRoot

{

   public ArrayList<String> commands;

   public ExecuteAsRoot(ArrayList<String> arr) {

      commands = new ArrayList<String>();

      for (int i=0; i<arr.size(); i++)

           commands.add(arr.get(i));

   }

   public boolean execute() {

       boolean retVal = false;  

       try {

          if (null != commands && commands.size() > 0) {         

             Process suProcess = Runtime.getRuntime().exec("su");

             DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());

             for (String currCommand : commands) {

                os.writeBytes(currCommand + "\n");

                os.flush();

             }

             os.writeBytes("exit\n");

             os.flush();

             BufferedReader stderr = new BufferedReader(new InputStreamReader(suProcess.getErrorStream()));

             String line = "";

             String errString = "";

             while ((line = stderr.readLine()) != null) errString += line + "\n";

             suProcess.waitFor();

             if (suProcess.exitValue() != 0)

                throw new Exception(errString);

            retVal = true;

         }

     } catch (Exception e) {

         retVal = false;

         Log.d("ERR", e.getMessage());

         e.printStackTrace();

     }     

  return retVal;

  }

}

A part of application code to control FlexCAN interface;

// ....

public boolean createVirtualCANInterface(String interfaceName) {

  ArrayList<String> commands = new ArrayList<String>();

  commands.add("ip link add dev " + interfaceName + " type vcan");

  ExecuteAsRoot p = new ExecuteAsRoot(commands);

  return p.execute();

}

public boolean setBitRate(String interfaceName, long bitrate) {

  ArrayList<String> commands = new ArrayList<String>();

  commands.add("ip link set " + interfaceName + " type can bitrate " + bitrate);

  ExecuteAsRoot p = new ExecuteAsRoot(commands);

  return p.execute();

}

public boolean startDevice(String interfaceName) {

  ArrayList<String> commands = new ArrayList<String>();

  commands.add("ip link set " + interfaceName + " up");

  ExecuteAsRoot p = new ExecuteAsRoot(commands);

  return p.execute();

}

public boolean stopDevice(String interfaceName) {

  ArrayList<String> commands = new ArrayList<String>();

  commands.add("ip link set " + interfaceName + " down");

  ExecuteAsRoot p = new ExecuteAsRoot(commands);

  return p.execute();

}

// ...

0 Kudos
2,271 Views
tommos23
Contributor III

Great work!
How did you root your i.MX6 android device and allow apps to run 'su' commands?

0 Kudos
2,271 Views
rickchu
Contributor IV

Hi,

In Android system, you can reference with this open source project. Only need do some modify that can working correctly on Android 4.2.

https://github.com/zhangjie201412/Flexcan

Rick

2,271 Views
kaancetinkaya
Contributor II

Thanks Rick,

I had seen this project before but I haven't tried it at all. I don't know whether this project gives an opportunity to configure/start/stop a CAN interface in code like I described in my question. I thought this one can be used to send and receive CAN frames only if an active CAN interface provided. But I may be wrong. Now, I'm heading to modify it based on my needs. I'll see what I can do with it. Thanks for your help.

My question is still valid though it would be nice to call those commands requiring system permissions in application code since it is not specific to use FlexCAN. I think I should ask for it in Android programming discussions in another day.

Kaan.

0 Kudos
2,271 Views
rickchu
Contributor IV

Hi Kaan,

This is a good example to add FlexCAN service support in Android; but you still need to modify to add extension control interface support for production usage for sure. We have based this example to develop FlexCAN framework support in our previous product. Just for your information.

Rick

0 Kudos