Calling ServiceManager.addService() with a different service's binder

1,401 views
Skip to first unread message

Anders Hasselqvist

unread,
Feb 4, 2011, 7:34:00 AM2/4/11
to android-...@googlegroups.com
Hi,

I wanted to have a service implemented in java that I could easily
access from native side as well
One way would be to add the service to the service manager by calling
ServiceManager.addService(), but to do that you need to run as system
uid.
Since the service also needed to write to the sdcard I couldn't run
all of the code in the service running as system uid.

I then experimented with a proxy approach by having two services.
Service 1 is running with its own uid that could write to the sdcard.
Service 2 is running with system uid. It will call bindService(Service
1), and in onServiceConnected() it would call
ServiceManager.addService() with the binder for Service 1.

This seems to be working fine when I run on my N1 device. Native side
can easily access the service through the default service manager and
call the functions of service 1.
But when running a generic build on the emulator I get occasional
ANR's when doing the rpc calls to service 1.

I know this is a bit of a hack, but I wouldn't have expected the ANR's.
Anyone has an idea why that could be happening?

Thanks,
Anders

Anders Hasselqvist

unread,
Feb 8, 2011, 1:26:03 AM2/8/11
to android-...@googlegroups.com
Hi,

I'll reduce my question a bit.

Is it valid to call ServiceManager.addService() with a binder received
by calling bindService() of a different service?
Or does the binder have to belong to the service that calls addService()?

Thanks,
Anders

Dianne Hackborn

unread,
Feb 8, 2011, 4:06:09 AM2/8/11
to android-...@googlegroups.com
I really don't understand what you are asking.  If you are mixing ServiceManager.addService and Context.bindService(), there is something fundamentally wrong -- these are two totally different ways to publish and retrieve IBinder instances for interacting with services, the former for core system services (that are always running for the life of the system), and the latter for everything else.

--
You received this message because you are subscribed to the Google Groups "android-platform" group.
To post to this group, send email to android-...@googlegroups.com.
To unsubscribe from this group, send email to android-platfo...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-platform?hl=en.




--
Dianne Hackborn
Android framework engineer
hac...@android.com

Note: please don't send private questions to me, as I don't have time to provide private support, and so won't reply to such e-mails.  All such questions should be posted on public forums, where I and others can see and answer them.

Anders Hasselqvist

unread,
Feb 8, 2011, 8:04:00 AM2/8/11
to android-...@googlegroups.com
Hi Dianne,

Thanks for the reply. I understand it seems weird.
I'll explain the problem that was attempted to be solved.

Basically it is a hack/abuse to make it easier to "port" an existing
client/server solution written in C/C++.

It was possible to wrap the server part with a Java service that
clients can connect to using Context.bindService().

But for the client side it was found that it is difficult to change
all cases to get the binder through bindService() in java.
It had to be done in native side. One way is to call
defaultServiceManager()->getService().
But for this to work the service has to be added by ServiceManager.addService().
To be allowed to call addService() the service needs to run with
shared uid system and be signed with the platform key.
This worked fine, except that the service also needs to write files to
the sdcard. The system user is not allowed to do that.

To work around this, the test with having a "proxy" service was done.
The "proxy" service runs with system uid and is allowed to call
ServiceManager.addService().
The proxy does a Context.bindService() to the service mentioned above.
When the binder is received it does ServiceManager.addService() with
the received binder.

This is definitely very hacky but seemed to be working fine on the N1.
There's issues when running in an emulator.
I was just trying to confirm how bad idea this was, and from your
response this seems to be a very bad idea. ;-)

Thanks,
Anders

Dianne Hackborn

unread,
Feb 8, 2011, 1:17:41 PM2/8/11
to android-...@googlegroups.com
No, it's not weird, it's wrong.  If you are writing your code as a Service, the way to access it is through bindService.  If you are writing a low-level system service (which means it MUST be running in a process that will never go away, so for Java code that is the system process), then it is published to the world through ServiceManager.  It doesn't make sense to mix these.

The only way to mix these is to do like telephony -- implement a system service part in the system process that provides the full interface to the service, and proxy calls to another process.  Note that when implementing this you must take care of cases like incoming calls to your service while the other process is gone and restarting.

Anders Hasselqvist

unread,
Feb 8, 2011, 9:07:43 PM2/8/11
to android-...@googlegroups.com
Hi Dianne,

Thanks for your response and the advice.

Regards,
Anders

Reply all
Reply to author
Forward
0 new messages