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.
We will edit the following files:
Filename |
Location |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
IActivityManager.java
.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.
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; }
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; }
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;
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; } }
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.
3.129.211.87