3

I'm working on a android library, so I wish to keep all the library code package private apart from a few classes which the library user needs to access.

Among these classes is an IntentService. However, the app crashes with this error :

java.lang.RuntimeException: Unable to instantiate service com.library.sdk.SaveDataIntentService: java.lang.IllegalAccessException: java.lang.Class<com.library.sdk.SaveDataIntentService> is not accessible from java.lang.Class<android.app.ActivityThread>
    at android.app.ActivityThread.handleCreateService(ActivityThread.java:3304)
    at android.app.ActivityThread.-wrap5(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1635)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6349)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)

Caused by: java.lang.IllegalAccessException: java.lang.Class<com.library.sdk.SaveDataIntentService> is not accessible from java.lang.Class<android.app.ActivityThread>
    at java.lang.Class.newInstance(Native Method)
    at android.app.ActivityThread.handleCreateService(ActivityThread.java:3301)
    at android.app.ActivityThread.-wrap5(ActivityThread.java) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1635) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6349) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783) 

Even the manifest shows a warning because the intent service is not declared as a public class.

What exactly is causing this and why does the intent service need to be public?

vepzfe
  • 4,217
  • 5
  • 26
  • 46
  • 1
    "Class.newInstance() will only succeed if the constructor is has zero arguments and is already accessible." (https://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html) - implying your class is not placed in the package `android.app`, it is invisible to `ActivityThread`. – Smutje Jan 18 '18 at 14:35

1 Answers1

4

What exactly is causing this

A Java class outside of your package needs to create an instance of your IntentService.

why does the intent service need to be public?

Because a Java class outside of your package cannot create an instance of a package-private class, nor can it invoke a package-private constructor.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thanks for that explanation @commonsware. A followup question - is there some way to hide the intent service from the library consumer while keeping it public? – vepzfe Jan 18 '18 at 18:27
  • @abhiank: No, sorry. The library consumer has as much rights to work with that class as the framework does. The library consumer cannot *do* much with an `IntentService`, though. – CommonsWare Jan 18 '18 at 18:52
  • Yeah, thats true. Since the library consumer doesn't the parameters and objects to pass to the intent service, which are package private so unknown to the consumer, he cant use it. Although, if he decompiles the code and looks up those constants, the lib consumer could use it and mess with the library logic. Another follow up question - is there someway to limit which component gets to call startService with my intent service? – vepzfe Jan 19 '18 at 09:53
  • @abhiank: "is there someway to limit which component gets to call startService with my intent service?" -- no, sorry. – CommonsWare Jan 19 '18 at 11:36