1

I have one very unusual case when calling an Android hidden API over reflection freezes the calling thread eternally. I cannot debug the underlying code as it is a code from Android itself normally not visible. I tried running the code in an asynctask, in a normal thread but nor asynctask.cancel nor thread.interrupt kills the thread, the thread stays visible, I can see it while debugging. Is it really not possible to run a code encapsulated and kill it completely eventually? This problems occurs only on Android O and only on some devices, that's why I need to test-run it to see if it works on the current device and be able to activate a feature according to that. The code below, I don't really see a solution for this:

Thread endCallThread;
Runnable myRunnable;

private void checkFeatureSupport(final Context context) {
    if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
            myRunnable = new Runnable() {
                @Override
                public void run() {
                    doInBackgroundWrapper();
                    if (getActivity() != null) {
                        getActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //handleResult();
                            }
                        });
                    }
                }
            };
            endCallThread = new Thread(myRunnable, "endCallThread");
            endCallThread.start();
            new CountDownTimer(3000, 3000) {
                public void onTick(long millisUntilFinished) {                        
                }

                public void onFinish() {
                    Log.e("TESTAUTOMATION", "endCall did not finished in 3 seconds");
                    // stop async task if not in progress
                    if (endCallThread.isAlive()) {
                        try {                                
                            endCallThread.interrupt();
                            endCallThread = null;
                            myRunnable = null;
                            System.gc();
                            Log.e("TESTAUTOMATION", "endCallThread interrupted");
                        } catch (Exception ex) {
                            Log.e("TESTAUTOMATION", "endCallThread interrupted exception");
                        }
                        //handleResult();                            
                    }
                }
            }.start();
        } else {
            mEndCallSupported = true;
        }
    }
}

private void doInBackgroundWrapper() {
    try {
        if (getContext() == null) {
            return;
        }
        final TelephonyManager telMan = (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
        if (telMan == null) {
            return;
        }
        final Class<?> classTemp = Class.forName(telMan.getClass().getName());
        final Method methodTemp = classTemp.getDeclaredMethod("getITelephony");
        methodTemp.setAccessible(true);
        ITelephony telephonyService = (ITelephony) methodTemp.invoke(telMan);
        // If this call does not return a security exception we say the call principally works.
        Log.d("TESTAUTOMATION", "endCall before");
        // This call endCall may freeze depending on device, mostly seen on Nexus 5x with Android 8&8.1
        telephonyService.endCall();
        Log.d("TESTAUTOMATION", "endCall after");
        mSupported = true;
    } catch (Exception ex) {
        ex.printStackTrace();
        mSupported = false;
    }
}

To reproduce this the device should better no have a SIM inserted.

David
  • 3,971
  • 1
  • 26
  • 65

1 Answers1

1

Thread.interrupt() in a common case does not stop a thread, it just marks specific boolean field (isInterrupted) as true. If a developer wants to stop thread's work at some point (after calling Thread.interrupt()) he can rely on this boolean filed Thread.isInterrupted() when he is implementing some work in a separate thread.

So I guess there is no such checking in the reflected hidden method what you are trying to call.

To stop your thread you can try deprecated Thread.stop() but it is a really bad practice.

Oleg Sokolov
  • 1,134
  • 1
  • 12
  • 19
  • Thanks. Thread.stop() does not work on Android, it returns java.lang.UnsupportedOperationException. – David Oct 03 '18 at 17:10