Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting "java.lang.reflect.InvocationTargetException" when trying to register broadcast receiver of embedded apk

My app has an embedded APK, I need to register a BroadcastReceiver in the inner APK from my main APK.

The inner APK is not to be installed on the system; I must load it dynamically. So, I'm using reflection to call a method in the inner APK which has code to register the BroadcastReceiver. This receiver of inner APK should invoke for related broadcast.

I'm getting an error while trying to register the BroadcastReceiver. Is it even possible for a BroadcastReceiver to be registered in this way, and be fully functional? Exception and code are given below

Error related log:

08-24 08:31:26.915: D/MainApp(1957): invoke method
08-24 08:31:26.955: D/InnerApp(1957): Register receiver
08-24 08:31:26.955: W/System.err(1957): java.lang.reflect.InvocationTargetException
08-24 08:31:26.965: W/System.err(1957):     at java.lang.reflect.Method.invokeNative(Native Method)
08-24 08:31:26.965: W/System.err(1957):     at java.lang.reflect.Method.invoke(Method.java:515)
08-24 08:31:26.965: W/System.err(1957):     at com.example.ea_mainapp.MainApp.invokeService(MainApp.java:105)
08-24 08:31:26.965: W/System.err(1957):     at com.example.ea_mainapp.MainApp.onCreate(MainApp.java:40)
08-24 08:31:26.965: W/System.err(1957):     at android.app.Activity.performCreate(Activity.java:5231)
08-24 08:31:26.975: W/System.err(1957):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
08-24 08:31:26.975: W/System.err(1957):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
08-24 08:31:26.975: W/System.err(1957):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
08-24 08:31:26.975: W/System.err(1957):     at android.app.ActivityThread.access$800(ActivityThread.java:135)
08-24 08:31:26.975: W/System.err(1957):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
08-24 08:31:26.975: W/System.err(1957):     at android.os.Handler.dispatchMessage(Handler.java:102)
08-24 08:31:26.975: W/System.err(1957):     at android.os.Looper.loop(Looper.java:136)
08-24 08:31:26.975: W/System.err(1957):     at android.app.ActivityThread.main(ActivityThread.java:5017)
08-24 08:31:26.975: W/System.err(1957):     at java.lang.reflect.Method.invokeNative(Native Method)
08-24 08:31:26.975: W/System.err(1957):     at java.lang.reflect.Method.invoke(Method.java:515)
08-24 08:31:26.975: W/System.err(1957):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
08-24 08:31:26.975: W/System.err(1957):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
08-24 08:31:26.975: W/System.err(1957):     at dalvik.system.NativeStart.main(Native Method)
08-24 08:31:26.985: W/System.err(1957): Caused by: java.lang.NullPointerException
08-24 08:31:26.985: W/System.err(1957):     at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:467)
08-24 08:31:26.985: W/System.err(1957):     at com.example.ea_innerapp.InnerApp.register(InnerApp.java:50)
08-24 08:31:26.985: W/System.err(1957):     ... 18 more`

Related code from Main app:

// invoke method
Log.d(TAG,"invoke method");

final String apkFile =TARGET_BASE_PATH+"EA_innerApp.apk";
String className = "com.example.ea_innerapp.InnerApp";
String methodToInvoke = "register"; 

final File optimizedDexOutputPath = getDir("outdex", 0);

DexClassLoader dLoader = new DexClassLoader(apkFile,optimizedDexOutputPath.getAbsolutePath(),
                null,ClassLoader.getSystemClassLoader().getParent());

try {
    Class<?> loadedClass = dLoader.loadClass(className);
    Object obj = (Object)loadedClass.newInstance();
    @SuppressWarnings("rawtypes")
    Class noparams[] = {};
    Method m = loadedClass.getMethod(methodToInvoke, noparams);
    Object oNoparams[] = {};
    m.invoke(obj, oNoparams);
} catch (ClassNotFoundException e) {....
} catch (InvocationTargetException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

Code of invoked method, "com.example.ea_innerapp.InnerApp.register":

Log.d(TAG, "Register receiver");
IntentFilter filter=new IntentFilter(); 
filter.addAction("com.example.ea_mainapp.i");
registerReceiver(obj_InnerReceiver,filter);
like image 364
blackfyre Avatar asked Aug 24 '15 12:08

blackfyre


1 Answers

I have fixed the issue.

Identification of issue:

Main section of exception staketrace was

08-24 08:31:26.985: W/System.err(1957): Caused by: java.lang.NullPointerException
08-24 08:31:26.985: W/System.err(1957):     at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:467)
08-24 08:31:26.985: W/System.err(1957):     at com.example.ea_innerapp.InnerApp.register(InnerApp.java:50)

I looked at code of "android.content.ContextWrapper.registerReceive" to find the main cause. Related code of class ContextWrapper is given below

464    @Override
465    public Intent registerReceiver(
466        BroadcastReceiver receiver, IntentFilter filter) {
467        return mBase.registerReceiver(receiver, filter);
468    }

Ref.: http://grepcode.com/file/repo1.maven.org/maven2/org.robolectric/android-all/4.4_r1-robolectric-1/android/content/ContextWrapper.java#ContextWrapper.0mBase

Error was at line 467, which is "return mBase.registerReceiver(receiver, filter);". Here, mBase is object of class "android.content.Context". Value of Context was null in class "com.example.ea_innerapp.InnerApp", since it is class of embedded apk. This is why I was getting exception.

Solution:

I needed to provide a Context value. So, I passed Context of main apk as argument to "com.example.ea_innerapp.InnerApp.register".

"com.example.ea_innerapp.InnerApp.register" was calling "android.content.ContextWrapper.registerReceive", which does not receive Context as parameter. So, I directly called "android.content.Context.registerReceiver", using the Context provided by main apk. Modified "com.example.ea_innerapp.InnerApp.register" is

public void register(Context param_ctx){        
        ......
        param_ctx.registerReceiver(obj_InnerReceiver,filter);   
    }

Note that you'll have to save the value of param_ctx and use it while un registering receiver as well, otherwise you'll get error. To unregister receiver you'll call

ctx.unregisterReceiver(obj_InnerReceiver); // ctx is the value that was passed to "com.example.ea_innerapp.InnerApp.register"
like image 129
blackfyre Avatar answered Oct 14 '22 22:10

blackfyre