1.介绍
frameworks\base\core\java\android\app\
frameworks\base\services\core\java\com\android\server\appop\
/**
* 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里申请权限的。
介绍
(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
//
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)
介绍
(1)AppOpsService构造函数
public AppOpsService(File storagePath, Handler handler) {
LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
mFile = new AtomicFile(storagePath, "appops"); //data/system/
mHandler = handler; //handler为AMS的MainHandler
mConstants = new Constants(mHandler);
readState(); //用于读取持久的信息
}
在ActivityManagerService中进行初始化:mAppOpsService = (new File(systemDir, “”), 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);
}
部分中的内容:
<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="" 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。