Marshmallow: Cannot execute Settings.System.canWrite (Context) from service

I have a NotificationListener service running in the background and it throws an exception when I run Settings.System.canWrite (Settings.java:3742)

12-03 18:25:33.490 2754-2771/? W/System.err﹕ java.lang.SecurityException: uid 10057 does not have android.permission.UPDATE_APP_OPS_STATS. 12-03 18:25:33.490 2754-2771/? W/System.err﹕ at android.os.Parcel.readException(Parcel.java:1599) 12-03 18:25:33.490 2754-2771/? W/System.err﹕ at android.os.Parcel.readException(Parcel.java:1552) 12-03 18:25:33.490 2754-2771/? W/System.err﹕ at com.android.internal.app.IAppOpsService$Stub$Proxy.checkOperation(IAppOpsService.java:327) 12-03 18:25:33.490 2754-2771/? W/System.err﹕ at android.app.AppOpsManager.checkOpNoThrow(AppOpsManager.java:1536) 12-03 18:25:33.490 2754-2771/? W/System.err﹕ at android.provider.Settings.isCallingPackageAllowedToPerformAppOpsProtectedOperation(Settings.java:8425) 12-03 18:25:33.490 2754-2771/? W/System.err﹕ at android.provider.Settings.isCallingPackageAllowedToWriteSettings(Settings.java:8320) 12-03 18:25:33.490 2754-2771/? W/System.err﹕ at android.provider.Settings$System.canWrite(Settings.java:3742) 

This is because the context provided is a service, because it does not happen when called from an action.

+6
source share
1 answer

This is a “bug”, although, as you said, this method should not be called from the NotificationListenerService . You should call it regular Activty or Service . I will explain later why.

In your wake, the following situation.

android.app.AppOpsManager.checkOpNoThrow (AppOpsManager.java:1536)

  /** * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it * returns {@link #MODE_ERRORED}. * @hide */ public int checkOpNoThrow(int op, int uid, String packageName) { try { return mService.checkOperation(op, uid, packageName); //1536 } catch (RemoteException e) { } return MODE_ERRORED; } 

Here he tries to catch RemoteException , although in Parcel ( android.os.Parcel.readException (Parcel.java:1599) ) this happens:

 public final void readException(int code, String msg) { switch (code) { case EX_SECURITY: throw new SecurityException(msg); // 1599 case EX_BAD_PARCELABLE: throw new BadParcelableException(msg); case EX_ILLEGAL_ARGUMENT: throw new IllegalArgumentException(msg); case EX_NULL_POINTER: throw new NullPointerException(msg); case EX_ILLEGAL_STATE: throw new IllegalStateException(msg); case EX_NETWORK_MAIN_THREAD: throw new NetworkOnMainThreadException(); case EX_UNSUPPORTED_OPERATION: throw new UnsupportedOperationException(msg); } throw new RuntimeException("Unknown exception code: " + code + " msg " + msg); } 

It throws a SecurityException .

As SecurityException NOT RemoteException try-catch fails to catch the exception in checkOpNoThrow , and you get an error message.

Moreover, if you try to use the application context (for example, this.getApplicationContext() ) instead of the listener service context, this will also result in an error. This is due to canWrite checking caller ID. The notification listener has a different UID from other parts of your application.

 public static boolean canWrite(Context context) { int uid = Binder.getCallingUid(); return isCallingPackageAllowedToWriteSettings(context, uid, getPackageNameForUid( context, uid), false); } 

EDIT

This error is tracked on tracking AOSP issues .

+3
source

All Articles