This API is not generally intended_project_me">
赞
踩
1.介绍
frameworks\base\core\java\android\app\AppOpsManager.java
frameworks\base\services\core\java\com\android\server\appop\AppOpsService.java
/**
* API for interacting with "application operation" tracking.
*
* <p>This API is not generally intended for third party application developers; most
* features are only available to system applications.
*/
就是应用程序操作管理。AppOpsManager是在API 19引入,即Android 4.3。且这个API不面向三方应用开发者;多数功能都只对系统应用可用。
AppOps虽然涵盖了App的权限管理,但是Google原生的设计并不仅仅是对“权限”的管理,而是对App的“动作”的管理。我们平时讲的权限管理多是针对具体的权限(App开发者在Manifest里申请的权限),而AppOps所管理的是所有可能涉及用户隐私和安全的操作,包括Turned on the screen, display toast等等,有些操作是不需要Manifest里申请权限的。
2.AppOpsManager介绍
(1).检测后的返回值
MODE_ALLOWED, // 0, 操作允许, Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is allowed to perform the given operation.
MODE_IGNORED, // 1, 操作不允许,但是checkOp不会抛出安全异常,表示忽略, Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is not allowed to perform the given operation,
// and this attempt should silently fail(it should not cause the app to crash).
MODE_ERRORED, // 2, 表示操作不允许,checkOp操作会抛出安全异常, Result from {@link #checkOpNoThrow}, {@link #noteOpNoThrow}, {@link #startOpNoThrow}: thegiven caller is not allowed to perform the given operation,
// and this attempt should cause it to have a fatal error, typically a {@link SecurityException}.
MODE_DEFAULT, // 3, 默认行为,可能进一步检查权限, Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller should use its default security check.
// This mode is not normally used; it should only be used with appop permissions, and callers must explicitly check for it and deal with it.
MODE_FOREGROUND, // 4, The only place you will this normally see this value is through {@link #unsafeCheckOpRaw}, which returns the actual raw mode of the op.
(2).相关常量
1).定义了一系列的OP:
...... public static final int OP_READ_CONTACTS = 4; /** @hide */ @UnsupportedAppUsage public static final int OP_WRITE_CONTACTS = 5; /** @hide */ @UnsupportedAppUsage public static final int OP_READ_CALL_LOG = 6; /** @hide */ @UnsupportedAppUsage public static final int OP_WRITE_CALL_LOG = 7; /** @hide */ @UnsupportedAppUsage public static final int OP_READ_CALENDAR = 8; /** @hide */ @UnsupportedAppUsage public static final int OP_WRITE_CALENDAR = 9; public static final int _NUM_OP = 91; ......
2).定义了相对应的OP Name:
...... /** Allows an application to read the user's contacts data. */ public static final String OPSTR_READ_CONTACTS = "android:read_contacts"; /** Allows an application to write to the user's contacts data. */ public static final String OPSTR_WRITE_CONTACTS = "android:write_contacts"; /** Allows an application to read the user's call log. */ public static final String OPSTR_READ_CALL_LOG = "android:read_call_log"; /** Allows an application to write to the user's call log. */ public static final String OPSTR_WRITE_CALL_LOG = "android:write_call_log"; /** Allows an application to read the user's calendar data. */ public static final String OPSTR_READ_CALENDAR = "android:read_calendar"; /** Allows an application to write to the user's calendar data. */ public static final String OPSTR_WRITE_CALENDAR = "android:write_calendar"; ......
3).定义了运行时权限及App Op权限:
// Warning: If an permission is added here it also has to be added to // com.android.packageinstaller.permission.utils.EventLogger private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = { // RUNTIME PERMISSIONS // Contacts OP_READ_CONTACTS, OP_WRITE_CONTACTS, OP_GET_ACCOUNTS, // Calendar OP_READ_CALENDAR, OP_WRITE_CALENDAR, // SMS OP_SEND_SMS, OP_RECEIVE_SMS, OP_READ_SMS, OP_RECEIVE_WAP_PUSH, OP_RECEIVE_MMS, OP_READ_CELL_BROADCASTS, // Storage OP_READ_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE, OP_ACCESS_MEDIA_LOCATION, // Location OP_COARSE_LOCATION, OP_FINE_LOCATION, // Phone OP_READ_PHONE_STATE, OP_READ_PHONE_NUMBERS, OP_CALL_PHONE, OP_READ_CALL_LOG, OP_WRITE_CALL_LOG, OP_ADD_VOICEMAIL, OP_USE_SIP, OP_PROCESS_OUTGOING_CALLS, OP_ANSWER_PHONE_CALLS, OP_ACCEPT_HANDOVER, // Microphone OP_RECORD_AUDIO, // Camera OP_CAMERA, // Body sensors OP_BODY_SENSORS, // Activity recognition OP_ACTIVITY_RECOGNITION, // Aural OP_READ_MEDIA_AUDIO, OP_WRITE_MEDIA_AUDIO, // Visual OP_READ_MEDIA_VIDEO, OP_WRITE_MEDIA_VIDEO, OP_READ_MEDIA_IMAGES, OP_WRITE_MEDIA_IMAGES, // APPOP PERMISSIONS OP_ACCESS_NOTIFICATIONS, OP_SYSTEM_ALERT_WINDOW, OP_WRITE_SETTINGS, OP_REQUEST_INSTALL_PACKAGES, OP_START_FOREGROUND, OP_SMS_FINANCIAL_TRANSACTIONS, };
4).定义了sOpToSwitch,及opToSwitch方法,通过数字得到相应的OP:
private static int[] sOpToSwitch = new int[] { OP_COARSE_LOCATION, // COARSE_LOCATION OP_COARSE_LOCATION, // FINE_LOCATION OP_COARSE_LOCATION, // GPS OP_VIBRATE, // VIBRATE OP_READ_CONTACTS, // READ_CONTACTS OP_WRITE_CONTACTS, // WRITE_CONTACTS OP_READ_CALL_LOG, // READ_CALL_LOG OP_WRITE_CALL_LOG, // WRITE_CALL_LOG OP_READ_CALENDAR, // READ_CALENDAR OP_WRITE_CALENDAR, // WRITE_CALENDAR OP_COARSE_LOCATION, // WIFI_SCAN OP_POST_NOTIFICATION, // POST_NOTIFICATION OP_COARSE_LOCATION, // NEIGHBORING_CELLS OP_CALL_PHONE, // CALL_PHONE OP_READ_SMS, // READ_SMS OP_WRITE_SMS, // WRITE_SMS OP_RECEIVE_SMS, // RECEIVE_SMS OP_RECEIVE_SMS, // RECEIVE_EMERGECY_SMS OP_RECEIVE_MMS, // RECEIVE_MMS OP_RECEIVE_WAP_PUSH, // RECEIVE_WAP_PUSH OP_SEND_SMS, // SEND_SMS OP_READ_SMS, // READ_ICC_SMS OP_WRITE_SMS, // WRITE_ICC_SMS OP_WRITE_SETTINGS, // WRITE_SETTINGS OP_SYSTEM_ALERT_WINDOW, // SYSTEM_ALERT_WINDOW OP_ACCESS_NOTIFICATIONS, // ACCESS_NOTIFICATIONS OP_CAMERA, // CAMERA OP_RECORD_AUDIO, // RECORD_AUDIO OP_PLAY_AUDIO, // PLAY_AUDIO OP_READ_CLIPBOARD, // READ_CLIPBOARD OP_WRITE_CLIPBOARD, // WRITE_CLIPBOARD OP_TAKE_MEDIA_BUTTONS, // TAKE_MEDIA_BUTTONS OP_TAKE_AUDIO_FOCUS, // TAKE_AUDIO_FOCUS OP_AUDIO_MASTER_VOLUME, // AUDIO_MASTER_VOLUME OP_AUDIO_VOICE_VOLUME, // AUDIO_VOICE_VOLUME OP_AUDIO_RING_VOLUME, // AUDIO_RING_VOLUME OP_AUDIO_MEDIA_VOLUME, // AUDIO_MEDIA_VOLUME OP_AUDIO_ALARM_VOLUME, // AUDIO_ALARM_VOLUME OP_AUDIO_NOTIFICATION_VOLUME, // AUDIO_NOTIFICATION_VOLUME OP_AUDIO_BLUETOOTH_VOLUME, // AUDIO_BLUETOOTH_VOLUME OP_WAKE_LOCK, // WAKE_LOCK OP_COARSE_LOCATION, // MONITOR_LOCATION OP_COARSE_LOCATION, // MONITOR_HIGH_POWER_LOCATION OP_GET_USAGE_STATS, // GET_USAGE_STATS OP_MUTE_MICROPHONE, // MUTE_MICROPHONE OP_TOAST_WINDOW, // TOAST_WINDOW OP_PROJECT_MEDIA, // PROJECT_MEDIA OP_ACTIVATE_VPN, // ACTIVATE_VPN OP_WRITE_WALLPAPER, // WRITE_WALLPAPER OP_ASSIST_STRUCTURE, // ASSIST_STRUCTURE OP_ASSIST_SCREENSHOT, // ASSIST_SCREENSHOT OP_READ_PHONE_STATE, // READ_PHONE_STATE OP_ADD_VOICEMAIL, // ADD_VOICEMAIL OP_USE_SIP, // USE_SIP OP_PROCESS_OUTGOING_CALLS, // PROCESS_OUTGOING_CALLS OP_USE_FINGERPRINT, // USE_FINGERPRINT OP_BODY_SENSORS, // BODY_SENSORS OP_READ_CELL_BROADCASTS, // READ_CELL_BROADCASTS OP_MOCK_LOCATION, // MOCK_LOCATION OP_READ_EXTERNAL_STORAGE, // READ_EXTERNAL_STORAGE OP_WRITE_EXTERNAL_STORAGE, // WRITE_EXTERNAL_STORAGE OP_TURN_SCREEN_ON, // TURN_SCREEN_ON OP_GET_ACCOUNTS, // GET_ACCOUNTS OP_RUN_IN_BACKGROUND, // RUN_IN_BACKGROUND OP_AUDIO_ACCESSIBILITY_VOLUME, // AUDIO_ACCESSIBILITY_VOLUME OP_READ_PHONE_NUMBERS, // READ_PHONE_NUMBERS OP_REQUEST_INSTALL_PACKAGES, // REQUEST_INSTALL_PACKAGES OP_PICTURE_IN_PICTURE, // ENTER_PICTURE_IN_PICTURE_ON_HIDE OP_INSTANT_APP_START_FOREGROUND, // INSTANT_APP_START_FOREGROUND OP_ANSWER_PHONE_CALLS, // ANSWER_PHONE_CALLS OP_RUN_ANY_IN_BACKGROUND, // OP_RUN_ANY_IN_BACKGROUND OP_CHANGE_WIFI_STATE, // OP_CHANGE_WIFI_STATE OP_REQUEST_DELETE_PACKAGES, // OP_REQUEST_DELETE_PACKAGES OP_BIND_ACCESSIBILITY_SERVICE, // OP_BIND_ACCESSIBILITY_SERVICE OP_ACCEPT_HANDOVER, // ACCEPT_HANDOVER OP_MANAGE_IPSEC_TUNNELS, // MANAGE_IPSEC_HANDOVERS OP_START_FOREGROUND, // START_FOREGROUND OP_COARSE_LOCATION, // BLUETOOTH_SCAN OP_USE_BIOMETRIC, // BIOMETRIC OP_ACTIVITY_RECOGNITION, // ACTIVITY_RECOGNITION OP_SMS_FINANCIAL_TRANSACTIONS, // SMS_FINANCIAL_TRANSACTIONS OP_READ_MEDIA_AUDIO, // READ_MEDIA_AUDIO OP_WRITE_MEDIA_AUDIO, // WRITE_MEDIA_AUDIO OP_READ_MEDIA_VIDEO, // READ_MEDIA_VIDEO OP_WRITE_MEDIA_VIDEO, // WRITE_MEDIA_VIDEO OP_READ_MEDIA_IMAGES, // READ_MEDIA_IMAGES OP_WRITE_MEDIA_IMAGES, // WRITE_MEDIA_IMAGES OP_LEGACY_STORAGE, // LEGACY_STORAGE OP_ACCESS_ACCESSIBILITY, // ACCESS_ACCESSIBILITY OP_READ_DEVICE_IDENTIFIERS, // READ_DEVICE_IDENTIFIERS OP_ACCESS_MEDIA_LOCATION, // ACCESS_MEDIA_LOCATION }; public static int opToSwitch(int op) { return sOpToSwitch[op]; }
5).定义了sOpToString,通过op得到其name:
private static String[] sOpToString = new String[]{ OPSTR_COARSE_LOCATION, OPSTR_FINE_LOCATION, OPSTR_GPS, OPSTR_VIBRATE, OPSTR_READ_CONTACTS, OPSTR_WRITE_CONTACTS, OPSTR_READ_CALL_LOG, OPSTR_WRITE_CALL_LOG, OPSTR_READ_CALENDAR, OPSTR_WRITE_CALENDAR, OPSTR_WIFI_SCAN, OPSTR_POST_NOTIFICATION, OPSTR_NEIGHBORING_CELLS, OPSTR_CALL_PHONE, OPSTR_READ_SMS, OPSTR_WRITE_SMS, OPSTR_RECEIVE_SMS, OPSTR_RECEIVE_EMERGENCY_BROADCAST, OPSTR_RECEIVE_MMS, OPSTR_RECEIVE_WAP_PUSH, OPSTR_SEND_SMS, OPSTR_READ_ICC_SMS, OPSTR_WRITE_ICC_SMS, OPSTR_WRITE_SETTINGS, OPSTR_SYSTEM_ALERT_WINDOW, OPSTR_ACCESS_NOTIFICATIONS, OPSTR_CAMERA, OPSTR_RECORD_AUDIO, OPSTR_PLAY_AUDIO, OPSTR_READ_CLIPBOARD, OPSTR_WRITE_CLIPBOARD, OPSTR_TAKE_MEDIA_BUTTONS, OPSTR_TAKE_AUDIO_FOCUS, OPSTR_AUDIO_MASTER_VOLUME, OPSTR_AUDIO_VOICE_VOLUME, OPSTR_AUDIO_RING_VOLUME, OPSTR_AUDIO_MEDIA_VOLUME, OPSTR_AUDIO_ALARM_VOLUME, OPSTR_AUDIO_NOTIFICATION_VOLUME, OPSTR_AUDIO_BLUETOOTH_VOLUME, OPSTR_WAKE_LOCK, OPSTR_MONITOR_LOCATION, OPSTR_MONITOR_HIGH_POWER_LOCATION, OPSTR_GET_USAGE_STATS, OPSTR_MUTE_MICROPHONE, OPSTR_TOAST_WINDOW, OPSTR_PROJECT_MEDIA, OPSTR_ACTIVATE_VPN, OPSTR_WRITE_WALLPAPER, OPSTR_ASSIST_STRUCTURE, OPSTR_ASSIST_SCREENSHOT, OPSTR_READ_PHONE_STATE, OPSTR_ADD_VOICEMAIL, OPSTR_USE_SIP, OPSTR_PROCESS_OUTGOING_CALLS, OPSTR_USE_FINGERPRINT, OPSTR_BODY_SENSORS, OPSTR_READ_CELL_BROADCASTS, OPSTR_MOCK_LOCATION, OPSTR_READ_EXTERNAL_STORAGE, OPSTR_WRITE_EXTERNAL_STORAGE, OPSTR_TURN_SCREEN_ON, OPSTR_GET_ACCOUNTS, OPSTR_RUN_IN_BACKGROUND, OPSTR_AUDIO_ACCESSIBILITY_VOLUME, OPSTR_READ_PHONE_NUMBERS, OPSTR_REQUEST_INSTALL_PACKAGES, OPSTR_PICTURE_IN_PICTURE, OPSTR_INSTANT_APP_START_FOREGROUND, OPSTR_ANSWER_PHONE_CALLS, OPSTR_RUN_ANY_IN_BACKGROUND, OPSTR_CHANGE_WIFI_STATE, OPSTR_REQUEST_DELETE_PACKAGES, OPSTR_BIND_ACCESSIBILITY_SERVICE, OPSTR_ACCEPT_HANDOVER, OPSTR_MANAGE_IPSEC_TUNNELS, OPSTR_START_FOREGROUND, OPSTR_BLUETOOTH_SCAN, OPSTR_USE_BIOMETRIC, OPSTR_ACTIVITY_RECOGNITION, OPSTR_SMS_FINANCIAL_TRANSACTIONS, OPSTR_READ_MEDIA_AUDIO, OPSTR_WRITE_MEDIA_AUDIO, OPSTR_READ_MEDIA_VIDEO, OPSTR_WRITE_MEDIA_VIDEO, OPSTR_READ_MEDIA_IMAGES, OPSTR_WRITE_MEDIA_IMAGES, OPSTR_LEGACY_STORAGE, OPSTR_ACCESS_ACCESSIBILITY, OPSTR_READ_DEVICE_IDENTIFIERS, OPSTR_ACCESS_MEDIA_LOCATION, };
6).列出了每个OP对应的权限,如果没有,则为null:
private static String[] sOpPerms = new String[] { android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION, null, android.Manifest.permission.VIBRATE, android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.WRITE_CONTACTS, android.Manifest.permission.READ_CALL_LOG, android.Manifest.permission.WRITE_CALL_LOG, android.Manifest.permission.READ_CALENDAR, android.Manifest.permission.WRITE_CALENDAR, android.Manifest.permission.ACCESS_WIFI_STATE, null, // no permission required for notifications null, // neighboring cells shares the coarse location perm android.Manifest.permission.CALL_PHONE, android.Manifest.permission.READ_SMS, null, // no permission required for writing sms android.Manifest.permission.RECEIVE_SMS, android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST, android.Manifest.permission.RECEIVE_MMS, android.Manifest.permission.RECEIVE_WAP_PUSH, android.Manifest.permission.SEND_SMS, android.Manifest.permission.READ_SMS, null, // no permission required for writing icc sms android.Manifest.permission.WRITE_SETTINGS, android.Manifest.permission.SYSTEM_ALERT_WINDOW, android.Manifest.permission.ACCESS_NOTIFICATIONS, android.Manifest.permission.CAMERA, android.Manifest.permission.RECORD_AUDIO, null, // no permission for playing audio null, // no permission for reading clipboard null, // no permission for writing clipboard null, // no permission for taking media buttons null, // no permission for taking audio focus null, // no permission for changing master volume null, // no permission for changing voice volume null, // no permission for changing ring volume null, // no permission for changing media volume null, // no permission for changing alarm volume null, // no permission for changing notification volume null, // no permission for changing bluetooth volume android.Manifest.permission.WAKE_LOCK, null, // no permission for generic location monitoring null, // no permission for high power location monitoring android.Manifest.permission.PACKAGE_USAGE_STATS, null, // no permission for muting/unmuting microphone null, // no permission for displaying toasts null, // no permission for projecting media null, // no permission for activating vpn null, // no permission for supporting wallpaper null, // no permission for receiving assist structure null, // no permission for receiving assist screenshot Manifest.permission.READ_PHONE_STATE, Manifest.permission.ADD_VOICEMAIL, Manifest.permission.USE_SIP, Manifest.permission.PROCESS_OUTGOING_CALLS, Manifest.permission.USE_FINGERPRINT, Manifest.permission.BODY_SENSORS, Manifest.permission.READ_CELL_BROADCASTS, null, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, null, // no permission for turning the screen on Manifest.permission.GET_ACCOUNTS, null, // no permission for running in background null, // no permission for changing accessibility volume Manifest.permission.READ_PHONE_NUMBERS, Manifest.permission.REQUEST_INSTALL_PACKAGES, null, // no permission for entering picture-in-picture on hide Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE, Manifest.permission.ANSWER_PHONE_CALLS, null, // no permission for OP_RUN_ANY_IN_BACKGROUND Manifest.permission.CHANGE_WIFI_STATE, Manifest.permission.REQUEST_DELETE_PACKAGES, Manifest.permission.BIND_ACCESSIBILITY_SERVICE, Manifest.permission.ACCEPT_HANDOVER, null, // no permission for OP_MANAGE_IPSEC_TUNNELS Manifest.permission.FOREGROUND_SERVICE, null, // no permission for OP_BLUETOOTH_SCAN Manifest.permission.USE_BIOMETRIC, Manifest.permission.ACTIVITY_RECOGNITION, Manifest.permission.SMS_FINANCIAL_TRANSACTIONS, null, null, // no permission for OP_WRITE_MEDIA_AUDIO null, null, // no permission for OP_WRITE_MEDIA_VIDEO null, null, // no permission for OP_WRITE_MEDIA_IMAGES null, // no permission for OP_LEGACY_STORAGE null, // no permission for OP_ACCESS_ACCESSIBILITY null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS Manifest.permission.ACCESS_MEDIA_LOCATION, };
7).给出了默认操作,通过opToDefaultMode方法得到默认值:
/** * This specifies the default mode for each operation. */ private static int[] sOpDefaultMode = new int[] { AppOpsManager.MODE_ALLOWED, // COARSE_LOCATION AppOpsManager.MODE_ALLOWED, // FINE_LOCATION AppOpsManager.MODE_ALLOWED, // GPS AppOpsManager.MODE_ALLOWED, // VIBRATE AppOpsManager.MODE_ALLOWED, // READ_CONTACTS AppOpsManager.MODE_ALLOWED, // WRITE_CONTACTS AppOpsManager.MODE_ALLOWED, // READ_CALL_LOG AppOpsManager.MODE_ALLOWED, // WRITE_CALL_LOG AppOpsManager.MODE_ALLOWED, // READ_CALENDAR AppOpsManager.MODE_ALLOWED, // WRITE_CALENDAR AppOpsManager.MODE_ALLOWED, // WIFI_SCAN AppOpsManager.MODE_ALLOWED, // POST_NOTIFICATION AppOpsManager.MODE_ALLOWED, // NEIGHBORING_CELLS AppOpsManager.MODE_ALLOWED, // CALL_PHONE AppOpsManager.MODE_ALLOWED, // READ_SMS AppOpsManager.MODE_IGNORED, // WRITE_SMS AppOpsManager.MODE_ALLOWED, // RECEIVE_SMS AppOpsManager.MODE_ALLOWED, // RECEIVE_EMERGENCY_BROADCAST AppOpsManager.MODE_ALLOWED, // RECEIVE_MMS AppOpsManager.MODE_ALLOWED, // RECEIVE_WAP_PUSH AppOpsManager.MODE_ALLOWED, // SEND_SMS AppOpsManager.MODE_ALLOWED, // READ_ICC_SMS AppOpsManager.MODE_ALLOWED, // WRITE_ICC_SMS AppOpsManager.MODE_DEFAULT, // WRITE_SETTINGS getSystemAlertWindowDefault(), // SYSTEM_ALERT_WINDOW AppOpsManager.MODE_ALLOWED, // ACCESS_NOTIFICATIONS AppOpsManager.MODE_ALLOWED, // CAMERA AppOpsManager.MODE_ALLOWED, // RECORD_AUDIO AppOpsManager.MODE_ALLOWED, // PLAY_AUDIO AppOpsManager.MODE_ALLOWED, // READ_CLIPBOARD AppOpsManager.MODE_ALLOWED, // WRITE_CLIPBOARD AppOpsManager.MODE_ALLOWED, // TAKE_MEDIA_BUTTONS AppOpsManager.MODE_ALLOWED, // TAKE_AUDIO_FOCUS AppOpsManager.MODE_ALLOWED, // AUDIO_MASTER_VOLUME AppOpsManager.MODE_ALLOWED, // AUDIO_VOICE_VOLUME AppOpsManager.MODE_ALLOWED, // AUDIO_RING_VOLUME AppOpsManager.MODE_ALLOWED, // AUDIO_MEDIA_VOLUME AppOpsManager.MODE_ALLOWED, // AUDIO_ALARM_VOLUME AppOpsManager.MODE_ALLOWED, // AUDIO_NOTIFICATION_VOLUME AppOpsManager.MODE_ALLOWED, // AUDIO_BLUETOOTH_VOLUME AppOpsManager.MODE_ALLOWED, // WAKE_LOCK AppOpsManager.MODE_ALLOWED, // MONITOR_LOCATION AppOpsManager.MODE_ALLOWED, // MONITOR_HIGH_POWER_LOCATION AppOpsManager.MODE_DEFAULT, // GET_USAGE_STATS AppOpsManager.MODE_ALLOWED, // MUTE_MICROPHONE AppOpsManager.MODE_ALLOWED, // TOAST_WINDOW AppOpsManager.MODE_IGNORED, // PROJECT_MEDIA AppOpsManager.MODE_IGNORED, // ACTIVATE_VPN AppOpsManager.MODE_ALLOWED, // WRITE_WALLPAPER AppOpsManager.MODE_ALLOWED, // ASSIST_STRUCTURE AppOpsManager.MODE_ALLOWED, // ASSIST_SCREENSHOT AppOpsManager.MODE_ALLOWED, // READ_PHONE_STATE AppOpsManager.MODE_ALLOWED, // ADD_VOICEMAIL AppOpsManager.MODE_ALLOWED, // USE_SIP AppOpsManager.MODE_ALLOWED, // PROCESS_OUTGOING_CALLS AppOpsManager.MODE_ALLOWED, // USE_FINGERPRINT AppOpsManager.MODE_ALLOWED, // BODY_SENSORS AppOpsManager.MODE_ALLOWED, // READ_CELL_BROADCASTS AppOpsManager.MODE_ERRORED, // MOCK_LOCATION AppOpsManager.MODE_ALLOWED, // READ_EXTERNAL_STORAGE AppOpsManager.MODE_ALLOWED, // WRITE_EXTERNAL_STORAGE AppOpsManager.MODE_ALLOWED, // TURN_SCREEN_ON AppOpsManager.MODE_ALLOWED, // GET_ACCOUNTS AppOpsManager.MODE_ALLOWED, // RUN_IN_BACKGROUND AppOpsManager.MODE_ALLOWED, // AUDIO_ACCESSIBILITY_VOLUME AppOpsManager.MODE_ALLOWED, // READ_PHONE_NUMBERS AppOpsManager.MODE_DEFAULT, // REQUEST_INSTALL_PACKAGES AppOpsManager.MODE_ALLOWED, // PICTURE_IN_PICTURE AppOpsManager.MODE_DEFAULT, // INSTANT_APP_START_FOREGROUND AppOpsManager.MODE_ALLOWED, // ANSWER_PHONE_CALLS AppOpsManager.MODE_ALLOWED, // RUN_ANY_IN_BACKGROUND AppOpsManager.MODE_ALLOWED, // CHANGE_WIFI_STATE AppOpsManager.MODE_ALLOWED, // REQUEST_DELETE_PACKAGES AppOpsManager.MODE_ALLOWED, // BIND_ACCESSIBILITY_SERVICE AppOpsManager.MODE_ALLOWED, // ACCEPT_HANDOVER AppOpsManager.MODE_ERRORED, // MANAGE_IPSEC_TUNNELS AppOpsManager.MODE_ALLOWED, // START_FOREGROUND AppOpsManager.MODE_ALLOWED, // BLUETOOTH_SCAN AppOpsManager.MODE_ALLOWED, // USE_BIOMETRIC AppOpsManager.MODE_ALLOWED, // ACTIVITY_RECOGNITION AppOpsManager.MODE_DEFAULT, // SMS_FINANCIAL_TRANSACTIONS AppOpsManager.MODE_ALLOWED, // READ_MEDIA_AUDIO AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_AUDIO AppOpsManager.MODE_ALLOWED, // READ_MEDIA_VIDEO AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_VIDEO AppOpsManager.MODE_ALLOWED, // READ_MEDIA_IMAGES AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_IMAGES AppOpsManager.MODE_DEFAULT, // LEGACY_STORAGE AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS AppOpsManager.MODE_ALLOWED, // ALLOW_MEDIA_LOCATION };
(3).AppOpsManager相关暴露方法
// 构造方法
AppOpsManager(Context context, IAppOpsService service) {
mContext = context;
mService = service;
}
// Do a quick check for whether an application might be able to perform an operation.
public int checkOp(int op, int uid, String packageName)
// Make note of an application performing an operation.
public int noteOp(int op, int uid, String packageName)
// Report that an application has started executing a long-running operation.
public int startOp(int op, int uid, String packageName)
// Do a quick check to validate if a package name belongs to a UID.
public void checkPackage(int uid, @NonNull String packageName)
// Report that an application is no longer performing an operation that had previously been started with {@link #startOp(int, int, String)}.
public void finishOp(int op, int uid, String packageName)
3.AppOpsService介绍
(1)AppOpsService构造函数
public AppOpsService(File storagePath, Handler handler) {
LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
mFile = new AtomicFile(storagePath, "appops"); //data/system/appops.xml
mHandler = handler; //handler为AMS的MainHandler
mConstants = new Constants(mHandler);
readState(); //用于读取appops.xml持久的信息
}
在ActivityManagerService中进行初始化:mAppOpsService = mInjector.getAppOpsService(new File(systemDir, “appops.xml”), mHandler);
PS:Injector类中:
public AppOpsService getAppOpsService(File file, Handler handler) {
return new AppOpsService(file, handler);
}
(2).内部类
static final class UidState { public final int uid; public int state = UID_STATE_CACHED; public int pendingState = UID_STATE_CACHED; public long pendingStateCommitTime; public int startNesting; public ArrayMap<String, Ops> pkgOps; public SparseIntArray opModes; // true indicates there is an interested observer, false there isn't but it has such an op public SparseBooleanArray foregroundOps; public boolean hasForegroundWatchers; ...... }
final static class Ops extends SparseArray<Op> {
final String packageName;
final UidState uidState;
final boolean isPrivileged;
......
}
final static class Op { int op; boolean running; final UidState uidState; final @NonNull String packageName; private @Mode int mode; private @Nullable LongSparseLongArray mAccessTimes; private @Nullable LongSparseLongArray mRejectTimes; private @Nullable LongSparseLongArray mDurations; private @Nullable LongSparseLongArray mProxyUids; private @Nullable LongSparseArray<String> mProxyPackageNames; int startNesting; long startRealtime; ...... }
Ops大概的数据结构,大概分为三个级别
(1). SparseArray mUidStates,用于存放uid和对应的uid下的状态,用UidState变量代表;
(2). UidState,一个uid对应一个UidState;一个uid可以对应多个package,每个package下面都有一个Ops代表一组操作;
(3). 每个Ops下又有多个op;
另外每个UidState下还有一组opModes,分别保存code和mode的对应管理;不过这个值来自于非pkg下的uid.
(3).相关函数说明
readState():解析pkg及uid标签
......
if (tagName.equals("pkg")) {
readPackage(parser);
} else if (tagName.equals("uid")) {
readUidOps(parser);
}
......
readPackage()的主要作用: 解析pkg标签下的uid标签
String pkgName = parser.getAttributeValue(null, "n");
......
if (tagName.equals("uid")) {
readUid(parser, pkgName);
} else {
Slog.w(TAG, "Unknown element under <pkg>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
......
readUid()的主要作用:得到应用的Privileged属性,解析uid标签下的op等标签
private void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException, XmlPullParserException, IOException { int uid = Integer.parseInt(parser.getAttributeValue(null, "n")); final UidState uidState = getUidStateLocked(uid, true); String isPrivilegedString = parser.getAttributeValue(null, "p"); boolean isPrivileged = false; if (isPrivilegedString == null) { try { IPackageManager packageManager = ActivityThread.getPackageManager(); if (packageManager != null) { ApplicationInfo appInfo = ActivityThread.getPackageManager() .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid)); if (appInfo != null) { isPrivileged = (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; } } else { // Could not load data, don't add to cache so it will be loaded later. return; } } catch (RemoteException e) { Slog.w(TAG, "Could not contact PackageManager", e); } } else { isPrivileged = Boolean.parseBoolean(isPrivilegedString); } int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tagName = parser.getName(); if (tagName.equals("op")) { readOp(parser, uidState, pkgName, isPrivileged); } else { Slog.w(TAG, "Unknown element under <pkg>: " + parser.getName()); XmlUtils.skipCurrentTag(parser); } } uidState.evalForegroundOps(mOpModeWatchers); }
readOp()的主要作用:解析op标签
private void readOp(XmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName, boolean isPrivileged) throws NumberFormatException, XmlPullParserException, IOException { Op op = new Op(uidState, pkgName, Integer.parseInt(parser.getAttributeValue(null, "n"))); final int mode = XmlUtils.readIntAttribute(parser, "m", AppOpsManager.opToDefaultMode(op.op)); op.mode = mode; int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tagName = parser.getName(); if (tagName.equals("st")) { final long key = XmlUtils.readLongAttribute(parser, "n"); final int flags = AppOpsManager.extractFlagsFromKey(key); final int state = AppOpsManager.extractUidStateFromKey(key); final long accessTime = XmlUtils.readLongAttribute(parser, "t", 0); final long rejectTime = XmlUtils.readLongAttribute(parser, "r", 0); final long accessDuration = XmlUtils.readLongAttribute(parser, "d", 0); final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp"); final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", 0); if (accessTime > 0) { op.accessed(accessTime, proxyUid, proxyPkg, state, flags); } if (rejectTime > 0) { op.rejected(rejectTime, proxyUid, proxyPkg, state, flags); } if (accessDuration > 0) { op.running(accessTime, accessDuration, state, flags); } } else { Slog.w(TAG, "Unknown element under <op>: " + parser.getName()); XmlUtils.skipCurrentTag(parser); } } if (uidState.pkgOps == null) { uidState.pkgOps = new ArrayMap<>(); } Ops ops = uidState.pkgOps.get(pkgName); if (ops == null) { ops = new Ops(pkgName, uidState, isPrivileged); uidState.pkgOps.put(pkgName, ops); } ops.put(op.op, op); }
部分appops.xml中的内容:
<uid n="10066"> //n代表uid <op n="0" m="1" /> //n代表code,m代表mode <op n="15" m="0" /> <op n="87" m="0" /> <op n="89" m="0" /> </uid> <pkg n="android"> // n代表name,即包名 <uid n="1000" p="true"> //n代表uid,p代表是否是预装在/system/priv-app/下(即isPrivileged) <op n="0" /> // n代表code <op n="3"> <st n="214748364801" t="1600740577341" d="75" /> //d代表间隔 </op> <op n="8"> <st n="214748364808" t="1600740495469" pp="com.android.providers.calendar" pu="10054" /> //st代表state,n代表key,t代表时间,pp代表代理包名,pu代表代理uid </op> <op n="40"> <st n="214748364801" t="1600768490988" d="2" /> </op> <op n="41"> <st n="214748364801" t="1600740532022" d="28588554" /> </op> <op n="43"> <st n="214748364801" r="1600768491106" /> //r代表拒绝时间 </op> </uid> </pkg>
(4).一些重要方法介绍
public void checkPackage(int uid, @NonNull String packageName)
这个方法会在uid下创建对应的uidState和一个Ops返回给用户,创建成功返回说明uid和packagename是对应的上的,返回AppOpsManager.MODE_ALLOWED,否则返回AppOpsManager.MODE_ERRORED
public int noteOp(int op, int uid, String packageName)
noteOp 函数比checkOp函数额外多出的功能就是会创建对应的op,另外会更新一些op操作的时间用于统计信息
public int startOp(int op, int uid, String packageName)
表示一个长时间运行的操作,比noteOp增加了一个统计信息,放在一个叫starting的集合里可以dump到,调用finishOp结束操作。
(5).权限检测
1).checkOp
public int checkOp(@NonNull String op, int uid, @NonNull String packageName) { return checkOp(strOpToOp(op), uid, packageName); } public int checkOp(int op, int uid, String packageName) { try { int mode = mService.checkOperation(op, uid, packageName); if (mode == MODE_ERRORED) { throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); } return mode; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } public int checkOperation(int code, int uid, String packageName) { return checkOperationInternal(code, uid, packageName, false /*raw*/); } // 最终调用到: private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, boolean raw) { if (isOpRestrictedDueToSuspend(code, packageName, uid)) { return AppOpsManager.MODE_IGNORED; } boolean isPrivileged; try { // 应用是否为priv-app isPrivileged = verifyAndGetIsPrivileged(uid, packageName); } catch (SecurityException e) { Slog.e(TAG, "checkOperation", e); return AppOpsManager.opToDefaultMode(code); } synchronized (this) { // 检查user多用户相关的权限 if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { return AppOpsManager.MODE_IGNORED; } // 根据code转换为op code,这里又进行了一个转换的操作 code = AppOpsManager.opToSwitch(code); // 获取UidState UidState uidState = getUidStateLocked(uid, false); if (uidState != null && uidState.opModes != null && uidState.opModes.indexOfKey(code) >= 0) { // 检查opModes下维护的code权限 final int rawMode = uidState.opModes.get(code); return raw ? rawMode : uidState.evalMode(code, rawMode); } // 获取pkg下的Op Op op = getOpLocked(code, uid, packageName, false, false); if (op == null) { // op不存在使用默认规则 return AppOpsManager.opToDefaultMode(code); } // op 存在返回op下的mode return raw ? op.mode : op.evalMode(); } }
2).noteOp
public int noteOp(@NonNull String op, int uid, @NonNull String packageName) { return noteOp(strOpToOp(op), uid, packageName); } public int noteOp(int op, int uid, String packageName) { final int mode = noteOpNoThrow(op, uid, packageName); if (mode == MODE_ERRORED) { throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); } return mode; } public int noteOpNoThrow(int op, int uid, String packageName) { try { return mService.noteOperation(op, uid, packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } public int noteOperation(int code, int uid, String packageName) { final CheckOpsDelegate delegate; synchronized (this) { delegate = mCheckOpsDelegate; } if (delegate == null) { return noteOperationImpl(code, uid, packageName); } return delegate.noteOperation(code, uid, packageName, AppOpsService.this::noteOperationImpl); } private int noteOperationImpl(int code, int uid, String packageName) { verifyIncomingUid(uid); verifyIncomingOp(code); String resolvedPackageName = resolvePackageName(uid, packageName); if (resolvedPackageName == null) { return AppOpsManager.MODE_IGNORED; } return noteOperationUnchecked(code, uid, resolvedPackageName, Process.INVALID_UID, null, AppOpsManager.OP_FLAG_SELF); } private int noteOperationUnchecked(int code, int uid, String packageName, int proxyUid, String proxyPackageName, @OpFlags int flags) { boolean isPrivileged; try { isPrivileged = verifyAndGetIsPrivileged(uid, packageName); } catch (SecurityException e) { Slog.e(TAG, "noteOperation", e); return AppOpsManager.MODE_ERRORED; } synchronized (this) { final Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, true /* edit */); if (ops == null) { scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid + " package " + packageName); return AppOpsManager.MODE_ERRORED; } final Op op = getOpLocked(ops, code, true); if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); return AppOpsManager.MODE_IGNORED; } final UidState uidState = ops.uidState; if (op.running) { final OpEntry entry = new OpEntry(op.op, op.running, op.mode, op.mAccessTimes, op.mRejectTimes, op.mDurations, op.mProxyUids, op.mProxyPackageNames); Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code " + code + " time=" + entry.getLastAccessTime(uidState.state, uidState.state, flags) + " duration=" + entry.getLastDuration( uidState.state, uidState.state, flags)); } final int switchCode = AppOpsManager.opToSwitch(code); // If there is a non-default per UID policy (we set UID op mode only if // non-default) it takes over, otherwise use the per package policy. if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) { final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode)); if (uidMode != AppOpsManager.MODE_ALLOWED) { if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " + packageName); op.rejected(System.currentTimeMillis(), proxyUid, proxyPackageName, uidState.state, flags); mHistoricalRegistry.incrementOpRejected(code, uid, packageName, uidState.state, flags); scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode); return uidMode; } } else { final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op; final int mode = switchOp.evalMode(); if (switchOp.mode != AppOpsManager.MODE_ALLOWED) { if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " + packageName); op.rejected(System.currentTimeMillis(), proxyUid, proxyPackageName, uidState.state, flags); mHistoricalRegistry.incrementOpRejected(code, uid, packageName, uidState.state, flags); scheduleOpNotedIfNeededLocked(code, uid, packageName, mode); return mode; } } if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid + " package " + packageName); op.accessed(System.currentTimeMillis(), proxyUid, proxyPackageName, uidState.state, flags); mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName, uidState.state, flags); scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_ALLOWED); return AppOpsManager.MODE_ALLOWED; } }
注意:
(1).一般的op都会走noteOperation,但是OP_RECORD_AUDIO却是不走这里,而是走checkOperation;
因为对于AUDIO有专门的方法checkAudioOperation,最终调用到checkOperation。
(2).checkOperation与noteOperation的区别可以查看checkOp及noteOp的函数说明:checkOp只是check;noteOp不仅check还note。至于具体调用哪个,看需求。一般的runtime权限都会进行check,少数非runtime也会check;多数非runtime权限会进行note,少数runtime权限也会note;这个看代码中的需求。
4.一般来说我们修改AppOps的机会比较少;但是在过CTA权限的时候,涉及到蓝牙、WLAN权限开关以及适配Android M之前的应用权限弹框等,需要修改AppOps的checkOperation及noteOperation。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。