android


Understanding Android Binders


I'm trying to understand a piece of code that uses Android Binders and Messages to perform IPC. I've read a few articles, papers and slides on binders, but I'm still confused and have a hard time understanding the code, since I didn't encounter any tutorials/examples of actually implementing binders in java code. I am listing down the sanitized/abbreviated code below as well as my understanding of what it does and where it gets confusing. I would appreciate if someone could help me understand this, especially pertaining to the flow of Parcels and Messages.
MyService.java
public class MyService extends Service
{
private final IMyService.Stub mBinder;
private Context _mContext;
private MyServiceHandler mHandler;
private HanderThread mHandlerThread;
private IHelperService mHelperService;
public MyService() {
this.mBinder = new IMyService.Stub() {
public void start_data(final String data) {
try {
if (MyService.this.mHelperService == null) {
return;
}
Message msg = MyService.this.getHandler().obtainMessage(3, (Object)data);
MyService.this.getHandler().sendMessage(msg);
} catch (SecurityException ex) {
// do some logging
}
};
}
private void startMessageProcess(final String message) {
// Process the message argument
final byte[] dataArray = this.getByteArray(message);
byte[] returnData;
try {
returnData = this.mHelperService.foo(dataArray);
} catch (Exception e) {
// do some logging
}
Message msg = this.getHandler().obtainMessage(3, (Object)message);
this.getHandler.sendMessage(msg);
}
private String getServerData(int id) {
// builds a Uri based on id and posts it, retrieves String data from HTTP entity and returns it
}
private boolean postDataToServer(final byte[] arrayData) {
// builds a Uri, post data to it, gets the status code, returns true if successful
}
private void sendData(final byte[] arrayData) {
final Intent intent = new Intent();
intent.setAction("com.my.service.intent.action.MY_RESULT");
intent.putExtra("com.my.service.intent.extra.RESULT", 0);
intent.putExtra("com.my.service.intent.extra.MY_DATA", arrayData);
this._mContext.sendBroadcast(intent, "com.my.service.permission.MY_PERMISSION");
}
public Handler getHandler() {
return this.mHandler;
}
public IBinder onBind(final Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (action != null && action.equals("com.my.service.intent.action.BIND_MY_SERVICE")) {
this._mContext = this.getApplicationContext();
return (IBinder)this.mBinder;
}
}
return null;
}
public void onCreate() {
super.onCreate();
try {
final Class<?> serviceManager = Class.forName("android.os.ServiceManager");
this.mHelperService = mHelperService.Stub.asInterface((IBinder)serviceManager.getMethod("getService", String.class).invoke(serviceManager, "helperservice"));
if (this.mHelperService == null) {
return;
}
}
catch (ClassNotFoundException ex2) {
Log.e("MyService", "Helper service ClassNotFoundException !!!");
}
catch (Exception ex) {
Log.e("MyService", "onCreate() Exception: " + Log.getStackTraceString((Throwable)ex));
}
this.mHandlerThread = new HandlerThread("MyService");
this.mHandlerThread.start();
this.mHandler = new MyServiceHandler(this.mHandlerThread.getLooper());
}
public int onStartCommand(final Intent intent, final int flags, final int startId) {
if (intent != null) {
super.onStartCommand(intent, flags, startId);
}
return START_NOT_STICKY;
}
private final class MyService Handler extends Handler
{
public MyServiceHandler(final Looper looper) {
super(looper);
}
public void handleMessage(final Message message) {
if (message != null) {
switch (message.what) {
case 2: {
final String data = (String)message.obj;
if (data != null) {
MyService.this.startMessageProcess(data);
return
}
break;
}
case 3: {
MyService.this.sendData((byte[])message.obj);
}
}
}
}
}
}
IMyService.java
public interface IMyService extends IInterface
{
void start_data(final String p0) throws RemoteException;
public abstract static class Stub extends Binder implements IMyService
{
public Stub() {
this.attachInterface((IInterface)this, "com.my.service.IMyService");
}
public static IMyService asInterface(final IBinder binder) {
if (binder == null) {
return null;
}
final IInterface queryLocalInterface = binder.queryLocalInterface("com.my.service.IMyService");
if (queryLocalInterface != null && queryLocalInterface instanceof IMyService) {
return (IMyService)queryLocalInterface;
}
return new Proxy(binder);
}
public IBinder asBinder() {
return (IBinder)this;
}
public boolean onTransact(final int code, final Parcel data, final Parcel reply, final int flags) throws RemoteException {
switch (code) {
case 1: {
data.enforceInterface("com.my.service.IMyService");
this.start_data(data.readString());
reply.writeNoException();
return true;
}
case 1000000000: {
reply.writeString("com.my.service.IMyService");
return true;
}
default: {
return super.onTransact(n, data, reply, flags);
}
}
}
private static class Proxy implements IMyService
{
private IBinder mRemote;
Proxy(final IBinder mRemote) {
this.mRemote = mRemote;
}
public IBinder asBinder() {
return this.mRemote;
}
public String getInterfaceDescriptor() {
return "com.my.service.IMyService";
}
#Override
public void start_data(final String data) throws RemoteException {
final Parcel data = Parcel.obtain();
final Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken("com.my.service.IMyService");
data.writeString(data);
this.mRemote.transact(1, data, reply, 0);
reply.readException();
}
finally {
reply.recycle();
data.recycle();
}
}
}
}
}
IHelperService.java
public interface IHelperService extends IInterface
{
// a bunch of method declarations here
public abstract static class Stub extends Binder implements IHelperService
{
public Stub() {
this.attachInterface((IInterface)this, "android.service.helper.IHelperService");
}
public static IHelperService asInterface(final IBinder binder) {
if (binder == null) {
if (queryLocalInterface != null && queryLocalInterface instanceof IHelperService) {
return (IHelperService)queryLocalInterface;
}
return new Proxy(binder);
}
}
public IBinder asBinder() {
return (IBinder)this;
}
public boolean onTransact(int code, final Parcel data, final Parcle reply, int flags) throws RemoteException {
switch (code) {
// does a bunch of bunch of stuff here based on the incoming code
}
}
}
private static class Proxy implements IHelperService
{
private IBinder mRemote;
Proxy(final IBinder mRemote) {
this.mRemote = mRemote;
}
#Override
// a bunch of method definitions here, everything that was declared above
}
}
I'm having a hard time tracing who sends what to who. For example, in the Proxy of IMyService, start_data calls transact(mRemote), but who is mRemote? Also, in the MyService() constructor as well as startMessageProcess, there are calls to sendMessage, who is it sending to?
Then, there are private methods in MyService that don't seem to be called locally, such as startMessageProcess and getServerData. Who else can call these methods if they're private?
Thanks!

Related Links

Android: How to set culture values for application
One method for several buttons?
How adjust the drawable in seek bar
How to Change Visibility of an ImageButton within a PagerAdapter?
Trouble using sharedPreferences between two activities
Move Android bitmap/canvas away from the top left
Populate Android Gallery from image file paths?
How to determine if a home screen shortcut exists?
Sqlite close() was never explicitly called on database - I tried but failed
ftrace on android?
Missing separator when trying to ndk build
Access profile images of the people from their twitter account in Android
How to get images with respect to the selection of custom Localization?
set cache image as contact photo
Buttons with multiline text sink under alignment line, how to fix it?
Where to invoke a notification dialog box in a program with two classes

Categories

HOME
uml
fabricjs
turing-machines
linkedin
rdbms
static
knitr
google-cloud-functions
zip
vsm
google-cloud-datalab
owin
altera
null-pointer
sse
lilypond
inno-download-plugin
event-store
tiki-wiki
custom-post-type
fractions
complex-numbers
cart
jbutton
android-sugarorm
vue-chartjs
swagger-php
zoomify
dm-script
amazon-ses
protein-database
ogc
stringtokenizer
wmp
oracle-service-bus
photos
vaadin-elements
dynamic-linq
ntvs
libgphoto2
twilio-click-to-call
manova
corruption
singleinstance
jqchart
check-mk
template-toolkit
donations
stripe-connect
pytables
grails-plugin
qtplugin
xcode-server
mongodb-php
nikeplus-api
freepbx
html-to-pdf
opl
tfs-workitem
themoviedb-api
computer-architecture
coda
typemock
procedural-programming
cosine-similarity
webfinger
cocos3d
genymotion-call
paw
lambda-architecture
clickbank
syndicationfeed
mt4j
artemis
jammer
mongohq
beaker-testing
zope.interface
lambdaj
failing-tests
stress
commerceserver2007
ruby-1.8
delimited-text
easyb
pagemethods
google-wave
fdf
netbeans6.1

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App