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

Realtime team sync for Android Studio
Failed to sync gradle project in Android Studio
Andoid outgoing call detect dialog presses from the other side
Passing current location data to my asynctask class
Package name and finger print doesnot match
Android - back from Contacts intent without selecting one
Cannot create table with SqliteOpenHelper [duplicate]
Genymotion - disappears from Android Device Monitor on OSX after closing/opening laptop lid
TextWatcher that changes two ListViews with two custom ArrayAdapters
Android, JUnit, EasyMock, PowerMock - how to properly delegate a static method?
Sync android map with a SQLite database on a server [closed]
Error converting bytecode to dex - Multiple dex files define
java.lang.NoClassDefFoundError: Failed resolution of: Ljava/time/LocalTime;
RecyclerView Adapter is laggy because of onBindViewHolder()
Intent.AppChooser crashing the app
Can't change selected item's background color in Navigation Drawer

Categories

HOME
sonarqube
pagination
alexa-skills-kit
formal-languages
flex
jelastic
sh
seo
google-cloud-functions
soa
x264
missing-data
lanczos
pcl-crypto
resultset
redis-sentinel
cmdb
scrolltop
bitnami
do-while
modbus-tcp
alpacajs
symfony-2.8
firefox-addon
poedit
cgbitmapcontext
systemtime
parcelable
event-store
definitelytyped
asymptotic-complexity
apktool
soot
ceylon
failover
ntp
panoramas
event-flow
gojs
instantiation
installscript
yowsup
xajax
openalpr
jpad
reactivekit
linqpad
microsoft-metro
glm-math
ssrs-2014
smoothstate.js
contract
angular-http
show-hide
monkey-testing
opencmis
truezip
java-websocket
rsa-archer-grc
atlas
pytables
omxplayer
actor-platform
adafruit
greatest-n-per-group
i386
delta
jclouds
respondcms
appscale
http-status-code-401
deep
spreadjs
cda
dbamp
html-to-pdf
nio2
toast
character-replacement
java-money
include-guards
binomial-theorem
dnssec
apache-spark-1.3
infosphere-spl
android-cookiemanager
metatrader5
webfinger
teaspoon
wcm
create.js
alternate
multiautocompletetextview
modular
cmmi
dolby-audio-api
composite-component
wp7test
pdfviewer
xcode3.2
failing-tests
jquery-address
ikimagebrowserview
drawtobitmap
inline-formset
ie-compatibility-mode
interprocess
scrollbars
django-piston
skype4java
tui
mathematical-notation
linfu-dynamicproxy
business-model
lemmatization

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