Book Image

Instant Android Systems Development How-to

By : Earlence Fernandes
Book Image

Instant Android Systems Development How-to

By: Earlence Fernandes

Overview of this book

<p>Android is by far the most popular open source mobile operating system. Learning to write high quality code at the platform level and learning how the systems works internally is a vital skill. This book teaches you these skills with clear and concise explanations and code examples.</p> <p>Instant Android Systems Development How-to provides a gentle introduction to the platform internals without sacrificing depth. Source code examples are designed to be meaningful, but at the same time, do not disguise their real purpose, which is to illustrate systems development techniques and common design patterns in android systems programming. Readers will be guided through several examples that give a hands-on experience.</p> <p>Readers begin by downloading the android source code, which is a topic of much discussion on android forums. They are then guided through the android boot process, and later on learn various common android systems development paradigms. More importantly, the book provides advice on when to use certain techniques which is often a mystery for the novice developer. Readers who complete the book will have high confidence in developing good systems code for Android.</p> <p>The book discusses how to setup a development machine and how to obtain the android source code and kernel code. It describes the source code organization and how the system boots up with precise references to various points in the source code. It highlights the common systems design patterns followed and how to create a custom system service. It then covers the all important flashing of phones. This is a topic of much confusion and the book provides direct steps to achieve safe flashing of developer phones. It describes the user application library mechanism and the platform library mechanism. Native code is needed for certain operations and an example service utilizing native code is explained. Modification of core system applications is explained and useful tips are provided on how to speed up the build-test cycle. The book concludes with a case study of two real world android platform extensions which give the user a reference while developing their own extensions.</p> <p>Instant Android Systems Development How-to is a well rounded book on platform internals that provides simple explanations without sacrificing depth and rigor.</p>
Table of Contents (7 chapters)
Instant Android Systems Development How-to
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Free Chapter
1
Instant Android Systems Development How-to

Adding a custom method to the Activity Manager service (Should know)


In this example, we will guide you through the steps needed to introduce a custom permission and learn how to make use of it to protect a method we add to the Activity Manager service.

Getting ready

We will edit the following files:

Filename

Location

ActivityManagerService.java

ANDROID_SRC/frameworks/base/services/java/com/android/server/am

ActivityManagerNative.java

ANDROID_SRC/frameworks/base/core/java/android/app

ActivityManager.java

ANDROID_SRC/frameworks/base/core/java/android/app

IActivityManager.java

ANDROID_SRC/frameworks/base/core/java/android/app

AndroidManifest.xml

ANDROID_SRC/frameworks/base/core/res

strings.xml

ANDROID_SRC/frameworks/base/core/res/res/values

How to do it...

  1. We begin by adding a new transaction and method prototype to IActivityManager.java.

  2. The following code is appended to IActivityManager.java:

    //Packt - Add this towards the end of the file
    int PACKT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 118;
    public int packtSensitiveMethod(int data) throws RemoteException;

    The number 118 is just 1 plus the last transaction number I have on my version of the source code. The ones you may see may differ. Use whatever number you see in your version and add one to it.

  3. The preceding lines basically set a transaction number for our method. Since the underlying binder driver uses these numbers to match which methods need to be performed when an IPC call is made, we set our method's transaction number to be one plus the last transaction known. Depending on the source code version you are working with, the number written above may have to be increased. The logic is simply adding 1 to the last transaction number you see. The IPC method needs to throw a RemoteException since this is mandated by the Binder IPC protocol. We then create the public interface for this method. To do this, add the following lines to ActivityManager.java, towards the end of the file:

     /* 
        Packt sensitive method demo 
        */ 
        public int packtSensitiveMethod(int data) 
        { 
          try { 
            return ActivityManagerNative.getDefault().packtSensitiveMethod(data); 
          } catch (RemoteException e) 
          { 
          } 
          return -1; 
        }
  4. This is a very simple method that does nothing useful. The aim of this recipe is to help you understand the mechanics of adding a new method to the Activity Manager service.

  5. Next, we will implement the marshalling code for this method. The concept of marshalling is no different than other interprocess frameworks. The basic aim is to serialize complex structures.

  6. Inside ActivityManagerNative.java, we make two changes. The first is inside the ActivityManagerProxy class that is inside the file. The code is organized in a way such that the ActivityManagerProxy class is towards the end of the file. Therefore, we write our proxy implementation of packtSensitiveMethod towards the end of the ActivityManagerNative.java file inside the scope of the ActivityManagerProxy class.

    The following code is added to ActivityManagerNative.java towards the end. It is the packtSensitiveMethod proxy implementation:

        //Packt 
        public int packtSensitiveMethod(int data) throws RemoteException 
        { 
          Parcel out = Parcel.obtain(); 
          Parcel reply = Parcel.obtain(); 
           
          out.writeInterfaceToken(IActivityManager.descriptor); 
          out.writeInt(data); 
           
          mRemote.transact(PACKT_TRANSACTION, out, reply, 0); 
           
          int result = reply.readInt(); 
           
          out.recycle(); 
          reply.recycle(); 
           
          return result; 
        }
  7. The second change is made in the onTransact method of the file. At the last case statement, we add our case code:

      //Packt 
            case PACKT_TRANSACTION: 
              data.enforceInterface(IActivityManager.descriptor); 
              int param = data.readInt(); 
              int result = packtSensitiveMethod(param); 
              reply.writeInt(result); 
              reply.writeNoException(); 
              return true;
  8. Finally, we have to implement this method. The following implementation is written inside ActivityManagerService.java:

    //===========================================================
    // PACKT 
    //=========================================================== 
        
        public int packtSensitiveMethod(int data) throws RemoteException 
        { 
          if(checkCallingPermission("packt.PACKT_PERMISSION") 
                           != PackageManager.PERMISSION_GRANTED) 
          { 
              throw new SecurityException("Requires permission packt.PACKT_PERMISSION"); 
            } 
            else 
            { 
            Log.i("PACKTinAMS", "sensitive method called with parameter: " + data); 
           
            return data * 2; 
          }
        }

Note

We have written the check permission code to secure this method. In the next recipe, I will guide you through the process of introducing a custom permission into the framework.

How it works...

In Android, the ActivityManagerService class executes within the context of the system server process. Hence, calls into it will be remote calls. Therefore, we have to make use of the Binder IPC mechanism. The IActivityManager.java file contains the set of remote calls exposed by the Activity Manager service. Hence, we add a new interface method packtSensitiveMethod() and a transaction constant PACKT_TRANSACTION that will correspond to this method.

ActivityManager.java represents a class library that user applications use to access the functionality of the Activity Manager service. This is similar to the custom class library we added in the earlier recipe on creating custom class libraries. As I've stated before, our implementations follow the design guidelines used in the Android code. Therefore, you will see several existing parallels in the Android source code. This is just one of the many examples that exist. Hence, we add a shim method to that file that invokes the real method through a remote procedure call.

As stated earlier, the Activity Manager service was written before the AIDL compiler existed, therefore the proxies and stubs for all remote calls are implemented manually. Hence, we add marshalling code to ActivityManagerNative.java.

You may wonder why we still add the marshalling code manually. The answer is that even though the AIDL compiler is now available, the build process was never updated for the ActivityManagerService class to make use of the AIDL compiler.