2015-12-03 16 views
6

NotificationListenerサービスがバックグラウンドで実行されていて、Settings.System.canWrite(Settings.java:3742)を実行すると例外がスローされますMarshmallow:サービスからSettings.System.canWrite(コンテキスト)を実行できません

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) 

これは、アクティビティから呼び出されたときに発生しないため、提供されたコンテキストがサービスであるためです。

答えて

3

これは「バグ」ですが、あなたが言ったように、このメソッドはNotificationListenerServiceからは呼び出されません。これは通常のActivtyまたはServiceから呼び出してください。私は後でそれを説明します。

あなたのトレースによると、以下のような状況があります。

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; 
    } 

ここでは、Parcel中もののRemoteExceptionをキャッチしようとしている(android.os.Parcel.readException(Parcel.java:1599))これが起こっている:

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); 
} 

それは、SecurityExceptionを投げています。

SecurityExceptionRemoteExceptionではありません。checkOpNoThrowでtry-catchが例外をキャッチできず、エラーが発生します。

さらに、リスナーサービスのコンテキストの代わりにアプリケーションのコンテキスト(たとえば、this.getApplicationContext())を使用しようとすると、エラーが発生します。これは、canWriteが発信者のUIDをチェックしているためです。通知リスナーには、アプリケーションの他の部分とは異なるUIDがあります。

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

EDIT

このバグはAOSP issue trackerに追跡されます。

+2

Android 6.0.1で再現 - – cuihtlauac

+0

あなたが書いた最後のコードは、アプリケーションのuidを取得して書き込み設定を確認するために使用されていますか?あなたが書いたコード – Olayinka

+0

> SDKのメソッドの実装です。はい、そうすることになっていますが、この場合、NotificationListenerServiceはアプリケーションの他の部分と同じプロセスで実行されず、予期しない問題が発生します。 – csenga

関連する問題