7

I posted a question about a new behavior of Android 5.1 that disables the Backup Service when setting up a device-owner on a device here...

A possible solution could be (I guess) to use reflection to fix the issue: I could find some reflection examples using a particular method in a hidden class, but this case looks more complicated, with a constructor that uses another hidden class (ServiceManager) etc. and I dunno how to do this...

The code that is annoying me is located in DevicePolicyManagerService.java (can be found here) on lines 3739 to 3749:

long ident = Binder.clearCallingIdentity();
try {
    IBackupManager ibm = IBackupManager.Stub.asInterface(
        ServiceManager.getService(Context.BACKUP_SERVICE));
    ibm.setBackupServiceActive(UserHandle.USER_OWNER, false);
} catch (RemoteException e) {
    throw new IllegalStateException("Failed deactivating backup service.", e);
} finally {
    Binder.restoreCallingIdentity(ident);
}

And my goal would be to re-enable the Backup Service, ideally this would call something like:

ibm.setBackupServiceActive(UserHandle.USER_OWNER, false);

Could you help me to do this ?

Community
  • 1
  • 1
JBA
  • 2,889
  • 1
  • 21
  • 38
  • What do you want to refactor? The IBackupManager instanciation? Where do you need reflexion? – Médéric May 27 '15 at 08:02
  • I need reflection because none of this is available... I need to revert what is done in this class DevicePolicyManagerService - Yes, that could mean get access to IBackupManager.Stub.asInterface(etc. stuff... , but this IBackupManager needs also access to non-accessible classes like ServiceManager or UserHandle, and non-accessible constants like Context.BACKUP_SERVICE or UserHandle.USER_OWNER... All examples I could find about reflection are very basic : 1 single class + 1 single method... it looks much more complex here (?) – JBA May 27 '15 at 12:31
  • (to see what I want to do you can take a look a the second code-block of my answer : this is what I'd like to do ideally) – JBA May 27 '15 at 12:32

1 Answers1

5

try this code:

    try {
        Class<?> iBackupManagerClass = Class.forName("android.app.backup.IBackupManager");
        Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager");
        Class<?>[] classes = iBackupManagerClass.getDeclaredClasses();
        Class<?> stubClass = null;
        for (Class clazz : classes) {
            if (clazz.getSimpleName().equals("Stub")) {
                stubClass = clazz;
            }
        }

        Method setBackupServiceActiveMethod = iBackupManagerClass.getMethod("setBackupServiceActive", int.class, boolean.class);
        Method asInterfaceMethod = stubClass.getMethod("asInterface", IBinder.class);
        Method getServiceMethod = serviceManagerClass.getMethod("getService", String.class);

        Object ibm = asInterfaceMethod.invoke(null, getServiceMethod.invoke(null, "backup"));
        setBackupServiceActiveMethod.invoke(ibm, 0, false);

    } catch (ClassNotFoundException e) {
        Log.e("TEST", e.getMessage(), e);
    } catch (NoSuchMethodException e) {
        Log.e("TEST", e.getMessage(), e);
    } catch (InvocationTargetException e) {
        Log.e("TEST", e.getMessage(), e);
    } catch (IllegalAccessException e) {
        Log.e("TEST", e.getMessage(), e);
    }

It will need some refactoring for error catching...

Médéric
  • 938
  • 4
  • 12
  • Thank you for this try, but I get an InvocationTargetException at the last line of the try { } block when doing setBackupServiceActiveMethod.invoke(ibm, 0, false); ... Maybe is this related to the lack of constants in the getServiceMethod that should take a Context.BACKUP_SERVICE constant, and the same for the method setBackupServiceActiveMethod that should get a UserHandle.USER_OWNER constant (?) - I'd like to try to add those constants by myself but dunno how to do this... – JBA May 27 '15 at 15:45
  • What was your stacktrace? I tried with a samsung galaxy s5 on android 5.1 and there was no error... – Médéric May 27 '15 at 16:26
  • 05-27 18:31:15.361: E/InvocationTargetException(5228): null 05-27 18:31:15.361: E/InvocationTargetException(5228): java.lang.reflect.InvocationTargetException 05-27 18:31:15.361: E/InvocationTargetException(5228): at java.lang.reflect.Method.invoke(Native Method) 05-27 18:31:15.361: E/InvocationTargetException(5228): at java.lang.reflect.Method.invoke(Method.java:372) 05-27 18:31:15.361: E/InvocationTargetException(5228): at com.dopapp.MainActivity.testReflection(MainActivity.java:836) .... and so on – JBA May 27 '15 at 16:32
  • Check if ibm is null before setBackupServiceActiveMethod.invoke(ibm, 0, false); – Médéric May 27 '15 at 16:34
  • So, with your code, on your S5, you can enable / disable the Backup Service ? – JBA May 27 '15 at 17:01
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/78955/discussion-between-jba-and-mederic). – JBA May 27 '15 at 22:22
  • After a few chat discussions it looks like we reached the limits of this exercise : we have SecurityExceptions meaning that we can probably not access those settings. If nothing relevant shows up I'll be glad to attribute the bounty because your reflection code is right even if at the end it does not work... – JBA May 28 '15 at 15:19