I am using the vndbinder to remotely call API in a binder service process.
All APIs work well but the one with a callback parameter is not running as expected.
The call sequence is showed in the blow diagram.
I tried A:
register the callback(let's call it CB1) so that the callback object is set on binder server side
pass the static member callback funtion(let's call it CB2) pointer to a C-style API and into the service child thread
service child thread triger the callback(3:callback in the diagram)
the CB2 run and prints the expected log, and then trys to trigger CB1(5:callback in the diagram), but the CB1 in binder client does not run.
I suspect there is something wrong with the backward communication from binder server to binder client, so
I tried B:
triger CB1 directly, but
CB1 in binder client is successfully run.
sequence
I tried as above, B is fine. But in A step 4 is not as expected. 5 and 6 is in a same static C++ style member function
Sorry that I can't show the code because of confidential reason.
erratum:
3 and 4 should be in service child thread. And I tried to create a child thread in which Callback 5 was tried to be triggering and it was not running on binder client either.
So the problem is transfered to "why callback function on binder client can not be triggered by binder server's child thread ?"
Related
anyone knows how i can make multiple instances of same service class work seperately, am working on a taxi meter app where i have a "Counter" service which will calculate for me the distance and add locations to database for each client, in my mainactivity i made three instance of the same service and started everyone seperately but it doesn't seem to work as expected(only i made a toast in every service start action but it seem to appear for just one client).
i know i have read in several treads that it's no possible to make multiple instance of services work at the same time but this is the only way i could do to make a taxi meter that supports multi clients at the same thing.
As rightly pointed out, we cannot have multiple instances of service. A service can only have one instance. Each subsequent call to startService, the method onStartCommand is called again.
But,suppose the onStartCommand instantiates a Timer object to repeat a task every 30 secs. Each subsequent call to startService, a new instance of object Timer is created...!
Now concider following use case:
timer is set up to log "Hello World" after every 30 sec
1st startService command is issued at 16:00:00
for next 2 mins, you should see 5 "Hello World" printed at
-16:00:00
-16:00:30
-16:01:00
-16:01:30
-16:02:00
Now 2nd startService command is issued at 16:02:10, for next 2 mins, you should see "Hello World" printed as follows:
-16:02:10 (2nd call)
-16:02:30 (1st call)
-16:02:40 (2nd call)
-16:03:00 (1st call)
-16:03:10 (...)
-16:03:30
-16:03:40
-16:04:00
So after 2nd call, two instances of the Timer class exist. But only one Service instance.
I have an app where I need to establish and maintain a bluetooth connection with another phone. However, this connection needs to remain alive even if the screen turns off.
So the way I've done this is 1) make it a service so the connection can exist in the background and 2) make an explicit call to start/stop the service instead of binding it to the activity (I believe if the screen goes off, the activity goes away, thus the service will stop)
This has now made things more complicated because my service has methods that I need to be able to manually invoke. For example, I want to start bluetooth discovery when the user clicks a button. So on button click, I need to tell this service to call my startDiscovery method. There are many situations like this (e.g. open a socket, pair to a device etc) where I need to manually call service methods
A lot of what I've read on this topic solves this by binding the service, but this I cannot do as explained earlier
Without binding, others suggest to use some sort of event bus, where on button click I send a message to the service. When it receives the message, it checks what type of message it is and then invokes the appropriate method.
OK, this works, but what if my method requires me to pass something into it? For example, lets say I have a list or something that I need to send over bluetooth. So I have a method in my Service that takes a list object, serializes it and sends it over BT to the other phone. But this doesn't seem possible with a basic messaging/event bus system
In sum, how do I pass an object through to a method in a service that is not bound to an activity, but instead has been manually started with startService?
I have seen this question here, but that method only seems to allow me to send objects when I start the service. In my case, the service is already started and sits in the background handling bluetooth traffic. I need to be able to invoke methods and pass objects while the service is already running
I have done something similar in my service. Sometimes i need to manually hide the notification that the service created. So i made the method public and static so it can be called anywhere like this:
public static void hideNotification(){
notificationManager.cancel(0);
}
Then call it in your activity like this: MyService.hideNotification()
EDIT
If you do not want a static method, you can create an empty constructor for your service and then when you need to call the method, create a new instance of your service and call it from that. For example:
In the service:
public class MyService extends Service{
public MyService(){}
public void hideNotification(){
notificationManager.cancel(0);
}
}
When you need to call a method:
MyService service = new Myservice();
service.hideNotification();
I read the docs on Android Developer about IBinder/Binder.
It says
The Binder system also supports recursion across processes. For
example if process A performs a transaction to process B, and process
B while handling that transaction calls transact() on an IBinder that
is implemented in A, then the thread in A that is currently waiting
for the original transaction to finish will take care of calling
Binder.onTransact() on the object being called by B. This ensures that
the recursion semantics when calling remote binder object are the same
as when calling local objects.
I have two questions about this
then the thread in A that is currently waiting for the original
transaction to finish will take care of calling Binder.onTransact() on
the object being called by B
First, how can a blocked thread be notified to do other stuff other than original procedure?
Second, After the thread finishes the onTransact(), will it block again to wait for original transaction.
First, How can a blocked thread be notified to do other stuff other than original procedure?
Binder is meant to abstract out the process of IPC, hence this question essentially simplifies to "how can a called function call a function before returning". Since that is clearly possible, and sensible, it should work with Binder too.
Implementation wise, it would be done by interpreting the data received from the binder transaction operation - if that is an encoding of "call this method for me" rather than "your return value is" then that is what will happen.
Second, After the thread finishes the onTransact(), will it block again to wait for original transaction.
Yes, because the method called out of the code that handles binder transactions will eventually return there (unless there's an exception, process death, signal or similar)
The concept of the application is simple: The user will interact with the interface, different messages will be sent to a remote server and the answer will show in the screen.
I have created a class called MessageInterface to deal with AsyncTask and the messages send/reception.
The data flow, since the user interacts with the interface, till he/she receive an answer, is this:
UI Element -> MessageInterface -> AsyncTask -> Android Socket -> Server
Server -> Android Socket -> AsyncTask -> MessageInterface -> ??
I have tried different solutions with ??. Calling to different MainActivty methods depending of the message received, creating a FragmentsInterface called by the MessageInterface to deal with the appropriate fragment... but none of them satisfies me.
This is my first project using sockets in Android, I have deal with sockets in other platforms (python, C, C++/Qt) and never felt so frustrated
Any suggestion for the architecture I should use?
Manuel, (I hope I got your question right)
The Async task has different methods as follows:
onPreExecute(): this run on the UI thread, you can touch any view of the main activity.
doInBackGroud(): this runs in its own thread, you CANNOT touch the views of the main activity.
onProgressUpdate(): This method runs in the UI thread, so you may touch (update) any view of the main activity, like for example show the message that has been received.
onPostExecute(): this method runs in the UI thread, you may touch any view of the main activity, but this method executes only once, when the doInbackGroud() method finishes.
With this in mind, in the doInbackGround() method you may call, whenever you want, the onProgressUpdate() method to update a TextView, Listview or whatever view you use to display the received message. You may pass a string to the onProgressUpdate or any object you prefer.
On the other hand, you can use a ConcurrentLinkedQueue to add the messages (Strings or Objects) in the UI and poll them in the doInBackGround process to send them to the server.
if you need an example of this, let me know and I'll send it to you.
Saludos.
I think I tracked down a memory leak and want to confirm what I think may true about how Android's Binder is implemented. In this case I have a Service and an Activity, each in their own process. I created an AIDL that allows me to pass a Callback object from the Activity to the Service through an ipc method and then have the callback called when the Service is done with the requested task.
For a long time I was wondering: if I pass a new Callback object to the Service and I don't keep a pointer to the Callback object in my Activity why doesn't the garbage collector just go ahead and collect the Callback in my Activity process? Since that doesn't seem to happen, how does the JVM know when to garbage collect the Callback in my Activity.
I think the answer is that the Binder system keeps a pointer to my Callback in the Activity process until the corresponding Callback object in the Service process has its finalize() method called, which then sends a message to the Activity to release the pointer. Is this correct? If not how does it work?
I believe it is and it leads to interesting situation where if the Callback in the Activity is pointing to something very memory intensive it won't be collected until the Callback in the Service is collected. If the Service isn't low on memory it might not collect the Callback for a long time and the Callbacks might just build up in the Activity until there is an OutOfMemoryError in the Activity.
Yury is pretty much correct.
My Service starts a thread that holds the callback and when the thread is done with its work it calls the callback and the thread ends. When the callback is called it may do a tiny bit of work in my Activity and then return at which point I don't have pointers in my Activity process to the callback.
However the callback object in the Activity will continue to be pointed to by Android's binder system until the corresponding callback object in the Service is garbage collected.
If the callback object in the Activity process dominates some other objects that consume a lot of memory then I am wasting memory in my Activity process for no good reason and could even get an OutOfMemoryError. The solution is to create a simple method in my callback class called destory() to null out all the callback's fields and to call that method when I am done with the callback.
If the callback class is a non-static inner class you may want to consider changing it to a static inner class and passing in the parent class in the constructor, this way you can null that out as well in the destory() method.
This brings up an interesting thought, if the parent class of a non-static inner callback class is an Activity and a configuration change happens (such as a screen rotation) after the callback is sent through the binder but before it is called back then the callback will be pointing to an old Activity object when it executes!
Update: I discovered this code inside Binder.java, of course it is disabled but it would have been nice if they mentioned this kind of stuff in the Javadocs.
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Binder> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
If I understand correctly how Binder works the problem in your case is the following. For each incoming incoming call your Service create a separate thread. When you pass an object to this thread your Binder system creates local copy of your object for the thread. Thus, until your Service method has returned result the thread with the copy of the object continues to work.
To check this just try to see the threads of your Service process (in DDMS).