2

When calling startActivity, one can try to catch an ActivityNotFoundException to know whether the activity exists.

When calling startService, however, there is no ServiceNotFoundException. How can I detect if the service exists?

Why do I want to do this

As I have learnt, a call to startService will be processed asynchronously, hence I would like to know whether I should expect a response (e.g. a callback, or a broadcast) from the service or not.

What have I done so far

I searched a bit and find a related question here. It seems that internally there is a ClassNotFoundException raised.

Is it possible to catch this exception somewhere? The Class.forName() method doesn't seem right ... or is it?

1 Answer 1

5

If it is your own service, you know whether your service exists. This issue only comes into play if you are trying to work with some third-party service. In that case, use PackageManager and queryIntentServices() to see if there is something that matches your Intent.

For example, in this sample app, I use queryIntentServices() to:

  • Confirm that there is only one match for my Intent

  • Convert it from an implicit Intent to an explicit Intent

  • Validate the signing key of the service, so that I know that it is not some service that is masquerading as the one I want to work with (e.g., repackaged app with malware)

Mostly, that is handled in onCreate() of the client fragment that will bind to the service:

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); appContext=(Application)getActivity().getApplicationContext(); Intent implicit=new Intent(IDownload.class.getName()); List<ResolveInfo> matches=getActivity().getPackageManager() .queryIntentServices(implicit, 0); if (matches.size() == 0) { Toast.makeText(getActivity(), "Cannot find a matching service!", Toast.LENGTH_LONG).show(); } else if (matches.size() > 1) { Toast.makeText(getActivity(), "Found multiple matching services!", Toast.LENGTH_LONG).show(); } else { ServiceInfo svcInfo=matches.get(0).serviceInfo; try { String otherHash=SignatureUtils.getSignatureHash(getActivity(), svcInfo.applicationInfo.packageName); String expected=getActivity().getString(R.string.expected_sig_hash); if (expected.equals(otherHash)) { Intent explicit=new Intent(implicit); ComponentName cn=new ComponentName(svcInfo.applicationInfo.packageName, svcInfo.name); explicit.setComponent(cn); appContext.bindService(explicit, this, Context.BIND_AUTO_CREATE); } else { Toast.makeText(getActivity(), "Unexpected signature found!", Toast.LENGTH_LONG).show(); } } catch (Exception e) { Log.e(getClass().getSimpleName(), "Exception trying to get signature hash", e); } } } 
Sign up to request clarification or add additional context in comments.

1 Comment

This looks exactly what I want. I will test it later.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.