package com.example.appopscheck; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; /** * AppOps状態確認用クラス */ public class AppOpsCheck { /* AppOpsService name from Context in android_4.3.0_r2.1 */ private static final String APP_OPS_SERVICE = "appops"; /* class and method names for reflection */ private static final String APP_OPS_MANAGER = "android.app.AppOpsManager"; private static final String CHECK_OP_NO_THROW = "checkOpNoThrow"; /* AppOps mode from AppOpsManager in android_4.3.0_r2.1 */ public static final int MODE_ALLOWED = 0; public static final int MODE_IGNORED = 1; public static final int MODE_ERRORED = 2; /* operation switch code from AppOpsmanager in android_4.3.0_r2.1 */ public static final int OP_NONE = -1; public static final int OP_COARSE_LOCATION = 0; public static final int OP_FINE_LOCATION = 1; public static final int OP_GPS = 2; public static final int OP_VIBRATE = 3; public static final int OP_READ_CONTACTS = 4; public static final int OP_WRITE_CONTACTS = 5; public static final int OP_READ_CALL_LOG = 6; public static final int OP_WRITE_CALL_LOG = 7; public static final int OP_READ_CALENDAR = 8; public static final int OP_WRITE_CALENDAR = 9; public static final int OP_WIFI_SCAN = 10; public static final int OP_POST_NOTIFICATION = 11; public static final int OP_NEIGHBORING_CELLS = 12; public static final int OP_CALL_PHONE = 13; public static final int OP_READ_SMS = 14; public static final int OP_WRITE_SMS = 15; public static final int OP_RECEIVE_SMS = 16; public static final int OP_RECEIVE_EMERGECY_SMS = 17; public static final int OP_RECEIVE_MMS = 18; public static final int OP_RECEIVE_WAP_PUSH = 19; public static final int OP_SEND_SMS = 20; public static final int OP_READ_ICC_SMS = 21; public static final int OP_WRITE_ICC_SMS = 22; public static final int OP_WRITE_SETTINGS = 23; public static final int OP_SYSTEM_ALERT_WINDOW = 24; public static final int OP_ACCESS_NOTIFICATIONS = 25; public static final int OP_CAMERA = 26; public static final int OP_RECORD_AUDIO = 27; public static final int OP_PLAY_AUDIO = 28; public static final int OP_READ_CLIPBOARD = 29; public static final int OP_WRITE_CLIPBOARD = 30; /* <operation number>-<operation name> from AppOpsManager in android_4.3.0_r2.1 */ private static String[] sOpNames = new String[]{ "COARSE_LOCATION", "FINE_LOCATION", "GPS", "VIBRATE", "READ_CONTACTS", "WRITE_CONTACTS", "READ_CALL_LOG", "WRITE_CALL_LOG", "READ_CALENDAR", "WRITE_CALENDAR", "WIFI_SCAN", "POST_NOTIFICATION", "NEIGHBORING_CELLS", "CALL_PHONE", "READ_SMS", "WRITE_SMS", "RECEIVE_SMS", "RECEIVE_EMERGECY_SMS", "RECEIVE_MMS", "RECEIVE_WAP_PUSH", "SEND_SMS", "READ_ICC_SMS", "WRITE_ICC_SMS", "WRITE_SETTINGS", "SYSTEM_ALERT_WINDOW", "ACCESS_NOTIFICATIONS", "CAMERA", "RECORD_AUDIO", "PLAY_AUDIO", "READ_CLIPBOARD", "WRITE_CLIPBOARD", }; private Context mContext; private Object mAppOpsManager; public AppOpsCheck(Context context) { mContext = context; mAppOpsManager = context.getSystemService(APP_OPS_SERVICE); } public int checkOp(int op, String packageName) { int appOpsMode = checkOpNoThrow(op, packageName); if (appOpsMode == MODE_ERRORED) { throw new SecurityException("Operation not allowed"); } return appOpsMode; } public int checkOpNoThrow(int op, String packageName) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { return MODE_ALLOWED; } if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) { return MODE_ALLOWED; } int appOpsMode = MODE_ERRORED; /* AppOpsManager.MODE_ERRORED */ Class appOpsClass = null; Method checkOpNoThrowMethod = null; try { int uid = getLinuxUidOfPackage(packageName); appOpsClass = Class.forName(APP_OPS_MANAGER); /* Context.APP_OPS_MANAGER */ checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class); Object ret = checkOpNoThrowMethod.invoke(mAppOpsManager, op, /* AppOpsManager.OP_READ_CONTACTS */ uid, /* Linux UID */ packageName ); appOpsMode = ((Integer) ret).intValue(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return appOpsMode; } /** * get operation number of operation name (like "GPS") * * @param name operation name * @return operation number if name is existing, otherwise -1 */ public int opNameToOp(String name) { return Arrays.asList(sOpNames).indexOf(name); } private int getLinuxUidOfPackage(String packageName) throws PackageManager.NameNotFoundException { PackageManager pm = mContext.getPackageManager(); return pm.getApplicationInfo(packageName, 0).uid; } }