/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app; import android.Manifest; import android.annotation.SystemApi; import android.app.usage.UsageStatsManager; import android.content.Context; import android.media.AudioAttributes.AttributeUsage; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.util.ArrayMap; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * API for interacting with "application operation" tracking. * *

This API is not generally intended for third party application developers; most * features are only available to system applications. Obtain an instance of it through * {@link Context#getSystemService(String) Context.getSystemService} with * {@link Context#APP_OPS_SERVICE Context.APP_OPS_SERVICE}.

*/ public class AppOpsManager { /** *

App ops allows callers to:

* * * *

Each operation is identified by a single integer; these integers are a fixed set of * operations, enumerated by the OP_* constants. * *

When checking operations, the result is a "mode" integer indicating the current * setting for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute * the operation but fake its behavior enough so that the caller doesn't crash), * MODE_ERRORED (throw a SecurityException back to the caller; the normal operation calls * will do this for you). */ final Context mContext; final IAppOpsService mService; final ArrayMap mModeWatchers = new ArrayMap(); static IBinder sToken; /** * Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is * allowed to perform the given operation. */ public static final int MODE_ALLOWED = 0; /** * 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). */ public static final int MODE_IGNORED = 1; /** * Result from {@link #checkOpNoThrow}, {@link #noteOpNoThrow}, {@link #startOpNoThrow}: the * given caller is not allowed to perform the given operation, and this attempt should * cause it to have a fatal error, typically a {@link SecurityException}. */ public static final int MODE_ERRORED = 2; /** * 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. */ public static final int MODE_DEFAULT = 3; // when adding one of these: // - increment _NUM_OP // - add rows to sOpToSwitch, sOpToString, sOpNames, sOpToPerms, sOpDefault // - add descriptive strings to Settings/res/values/arrays.xml // - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app) /** @hide No operation specified. */ public static final int OP_NONE = -1; /** @hide Access to coarse location information. */ public static final int OP_COARSE_LOCATION = 0; /** @hide Access to fine location information. */ public static final int OP_FINE_LOCATION = 1; /** @hide Causing GPS to run. */ public static final int OP_GPS = 2; /** @hide */ public static final int OP_VIBRATE = 3; /** @hide */ public static final int OP_READ_CONTACTS = 4; /** @hide */ public static final int OP_WRITE_CONTACTS = 5; /** @hide */ public static final int OP_READ_CALL_LOG = 6; /** @hide */ public static final int OP_WRITE_CALL_LOG = 7; /** @hide */ public static final int OP_READ_CALENDAR = 8; /** @hide */ public static final int OP_WRITE_CALENDAR = 9; /** @hide */ public static final int OP_WIFI_SCAN = 10; /** @hide */ public static final int OP_POST_NOTIFICATION = 11; /** @hide */ public static final int OP_NEIGHBORING_CELLS = 12; /** @hide */ public static final int OP_CALL_PHONE = 13; /** @hide */ public static final int OP_READ_SMS = 14; /** @hide */ public static final int OP_WRITE_SMS = 15; /** @hide */ public static final int OP_RECEIVE_SMS = 16; /** @hide */ public static final int OP_RECEIVE_EMERGECY_SMS = 17; /** @hide */ public static final int OP_RECEIVE_MMS = 18; /** @hide */ public static final int OP_RECEIVE_WAP_PUSH = 19; /** @hide */ public static final int OP_SEND_SMS = 20; /** @hide */ public static final int OP_READ_ICC_SMS = 21; /** @hide */ public static final int OP_WRITE_ICC_SMS = 22; /** @hide */ public static final int OP_WRITE_SETTINGS = 23; /** @hide */ public static final int OP_SYSTEM_ALERT_WINDOW = 24; /** @hide */ public static final int OP_ACCESS_NOTIFICATIONS = 25; /** @hide */ public static final int OP_CAMERA = 26; /** @hide */ public static final int OP_RECORD_AUDIO = 27; /** @hide */ public static final int OP_PLAY_AUDIO = 28; /** @hide */ public static final int OP_READ_CLIPBOARD = 29; /** @hide */ public static final int OP_WRITE_CLIPBOARD = 30; /** @hide */ public static final int OP_TAKE_MEDIA_BUTTONS = 31; /** @hide */ public static final int OP_TAKE_AUDIO_FOCUS = 32; /** @hide */ public static final int OP_AUDIO_MASTER_VOLUME = 33; /** @hide */ public static final int OP_AUDIO_VOICE_VOLUME = 34; /** @hide */ public static final int OP_AUDIO_RING_VOLUME = 35; /** @hide */ public static final int OP_AUDIO_MEDIA_VOLUME = 36; /** @hide */ public static final int OP_AUDIO_ALARM_VOLUME = 37; /** @hide */ public static final int OP_AUDIO_NOTIFICATION_VOLUME = 38; /** @hide */ public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39; /** @hide */ public static final int OP_WAKE_LOCK = 40; /** @hide Continually monitoring location data. */ public static final int OP_MONITOR_LOCATION = 41; /** @hide Continually monitoring location data with a relatively high power request. */ public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42; /** @hide Retrieve current usage stats via {@link UsageStatsManager}. */ public static final int OP_GET_USAGE_STATS = 43; /** @hide */ public static final int OP_MUTE_MICROPHONE = 44; /** @hide */ public static final int OP_TOAST_WINDOW = 45; /** @hide Capture the device's display contents and/or audio */ public static final int OP_PROJECT_MEDIA = 46; /** @hide Activate a VPN connection without user intervention. */ public static final int OP_ACTIVATE_VPN = 47; /** @hide Access the WallpaperManagerAPI to write wallpapers. */ public static final int OP_WRITE_WALLPAPER = 48; /** @hide Received the assist structure from an app. */ public static final int OP_ASSIST_STRUCTURE = 49; /** @hide Received a screenshot from assist. */ public static final int OP_ASSIST_SCREENSHOT = 50; /** @hide Read the phone state. */ public static final int OP_READ_PHONE_STATE = 51; /** @hide Add voicemail messages to the voicemail content provider. */ public static final int OP_ADD_VOICEMAIL = 52; /** @hide Access APIs for SIP calling over VOIP or WiFi. */ public static final int OP_USE_SIP = 53; /** @hide Intercept outgoing calls. */ public static final int OP_PROCESS_OUTGOING_CALLS = 54; /** @hide User the fingerprint API. */ public static final int OP_USE_FINGERPRINT = 55; /** @hide Access to body sensors such as heart rate, etc. */ public static final int OP_BODY_SENSORS = 56; /** @hide Read previously received cell broadcast messages. */ public static final int OP_READ_CELL_BROADCASTS = 57; /** @hide Inject mock location into the system. */ public static final int OP_MOCK_LOCATION = 58; /** @hide Read external storage. */ public static final int OP_READ_EXTERNAL_STORAGE = 59; /** @hide Write external storage. */ public static final int OP_WRITE_EXTERNAL_STORAGE = 60; /** @hide Turned on the screen. */ public static final int OP_TURN_SCREEN_ON = 61; /** @hide Get device accounts. */ public static final int OP_GET_ACCOUNTS = 62; /** @hide Control whether an application is allowed to run in the background. */ public static final int OP_RUN_IN_BACKGROUND = 63; /** @hide */ public static final int _NUM_OP = 64; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; /** Access to fine location information. */ public static final String OPSTR_FINE_LOCATION = "android:fine_location"; /** Continually monitoring location data. */ public static final String OPSTR_MONITOR_LOCATION = "android:monitor_location"; /** Continually monitoring location data with a relatively high power request. */ public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power"; /** Access to {@link android.app.usage.UsageStatsManager}. */ public static final String OPSTR_GET_USAGE_STATS = "android:get_usage_stats"; /** Activate a VPN connection without user intervention. @hide */ @SystemApi public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn"; /** 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"; /** Allows an application to initiate a phone call. */ public static final String OPSTR_CALL_PHONE = "android:call_phone"; /** Allows an application to read SMS messages. */ public static final String OPSTR_READ_SMS = "android:read_sms"; /** Allows an application to receive SMS messages. */ public static final String OPSTR_RECEIVE_SMS = "android:receive_sms"; /** Allows an application to receive MMS messages. */ public static final String OPSTR_RECEIVE_MMS = "android:receive_mms"; /** Allows an application to receive WAP push messages. */ public static final String OPSTR_RECEIVE_WAP_PUSH = "android:receive_wap_push"; /** Allows an application to send SMS messages. */ public static final String OPSTR_SEND_SMS = "android:send_sms"; /** Required to be able to access the camera device. */ public static final String OPSTR_CAMERA = "android:camera"; /** Required to be able to access the microphone device. */ public static final String OPSTR_RECORD_AUDIO = "android:record_audio"; /** Required to access phone state related information. */ public static final String OPSTR_READ_PHONE_STATE = "android:read_phone_state"; /** Required to access phone state related information. */ public static final String OPSTR_ADD_VOICEMAIL = "android:add_voicemail"; /** Access APIs for SIP calling over VOIP or WiFi */ public static final String OPSTR_USE_SIP = "android:use_sip"; /** Use the fingerprint API. */ public static final String OPSTR_USE_FINGERPRINT = "android:use_fingerprint"; /** Access to body sensors such as heart rate, etc. */ public static final String OPSTR_BODY_SENSORS = "android:body_sensors"; /** Read previously received cell broadcast messages. */ public static final String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts"; /** Inject mock location into the system. */ public static final String OPSTR_MOCK_LOCATION = "android:mock_location"; /** Read external storage. */ public static final String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage"; /** Write external storage. */ public static final String OPSTR_WRITE_EXTERNAL_STORAGE = "android:write_external_storage"; /** Required to draw on top of other apps. */ public static final String OPSTR_SYSTEM_ALERT_WINDOW = "android:system_alert_window"; /** Required to write/modify/update system settingss. */ public static final String OPSTR_WRITE_SETTINGS = "android:write_settings"; /** @hide Get device accounts. */ public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts"; private static final int[] RUNTIME_PERMISSIONS_OPS = { // 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, // Location OP_COARSE_LOCATION, OP_FINE_LOCATION, // Phone OP_READ_PHONE_STATE, OP_CALL_PHONE, OP_READ_CALL_LOG, OP_WRITE_CALL_LOG, OP_ADD_VOICEMAIL, OP_USE_SIP, OP_PROCESS_OUTGOING_CALLS, // Microphone OP_RECORD_AUDIO, // Camera OP_CAMERA, // Body sensors OP_BODY_SENSORS }; /** * This maps each operation to the operation that serves as the * switch to determine whether it is allowed. Generally this is * a 1:1 mapping, but for some things (like location) that have * multiple low-level operations being tracked that should be * presented to the user as one switch then this can be used to * make them all controlled by the same single operation. */ private static int[] sOpToSwitch = new int[] { OP_COARSE_LOCATION, OP_COARSE_LOCATION, OP_COARSE_LOCATION, OP_VIBRATE, OP_READ_CONTACTS, OP_WRITE_CONTACTS, OP_READ_CALL_LOG, OP_WRITE_CALL_LOG, OP_READ_CALENDAR, OP_WRITE_CALENDAR, OP_COARSE_LOCATION, OP_POST_NOTIFICATION, OP_COARSE_LOCATION, OP_CALL_PHONE, OP_READ_SMS, OP_WRITE_SMS, OP_RECEIVE_SMS, OP_RECEIVE_SMS, OP_RECEIVE_SMS, OP_RECEIVE_SMS, OP_SEND_SMS, OP_READ_SMS, OP_WRITE_SMS, OP_WRITE_SETTINGS, OP_SYSTEM_ALERT_WINDOW, OP_ACCESS_NOTIFICATIONS, OP_CAMERA, OP_RECORD_AUDIO, OP_PLAY_AUDIO, OP_READ_CLIPBOARD, OP_WRITE_CLIPBOARD, OP_TAKE_MEDIA_BUTTONS, OP_TAKE_AUDIO_FOCUS, OP_AUDIO_MASTER_VOLUME, OP_AUDIO_VOICE_VOLUME, OP_AUDIO_RING_VOLUME, OP_AUDIO_MEDIA_VOLUME, OP_AUDIO_ALARM_VOLUME, OP_AUDIO_NOTIFICATION_VOLUME, OP_AUDIO_BLUETOOTH_VOLUME, OP_WAKE_LOCK, OP_COARSE_LOCATION, OP_COARSE_LOCATION, OP_GET_USAGE_STATS, OP_MUTE_MICROPHONE, OP_TOAST_WINDOW, OP_PROJECT_MEDIA, OP_ACTIVATE_VPN, OP_WRITE_WALLPAPER, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT, OP_READ_PHONE_STATE, OP_ADD_VOICEMAIL, OP_USE_SIP, OP_PROCESS_OUTGOING_CALLS, OP_USE_FINGERPRINT, OP_BODY_SENSORS, OP_READ_CELL_BROADCASTS, OP_MOCK_LOCATION, OP_READ_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE, OP_TURN_SCREEN_ON, OP_GET_ACCOUNTS, OP_RUN_IN_BACKGROUND, }; /** * This maps each operation to the public string constant for it. * If it doesn't have a public string constant, it maps to null. */ private static String[] sOpToString = new String[] { OPSTR_COARSE_LOCATION, OPSTR_FINE_LOCATION, null, null, OPSTR_READ_CONTACTS, OPSTR_WRITE_CONTACTS, OPSTR_READ_CALL_LOG, OPSTR_WRITE_CALL_LOG, OPSTR_READ_CALENDAR, OPSTR_WRITE_CALENDAR, null, null, null, OPSTR_CALL_PHONE, OPSTR_READ_SMS, null, OPSTR_RECEIVE_SMS, null, OPSTR_RECEIVE_MMS, OPSTR_RECEIVE_WAP_PUSH, OPSTR_SEND_SMS, null, null, OPSTR_WRITE_SETTINGS, OPSTR_SYSTEM_ALERT_WINDOW, null, OPSTR_CAMERA, OPSTR_RECORD_AUDIO, null, null, null, null, null, null, null, null, null, null, null, null, null, OPSTR_MONITOR_LOCATION, OPSTR_MONITOR_HIGH_POWER_LOCATION, OPSTR_GET_USAGE_STATS, null, null, null, OPSTR_ACTIVATE_VPN, null, null, null, OPSTR_READ_PHONE_STATE, OPSTR_ADD_VOICEMAIL, OPSTR_USE_SIP, null, OPSTR_USE_FINGERPRINT, OPSTR_BODY_SENSORS, OPSTR_READ_CELL_BROADCASTS, OPSTR_MOCK_LOCATION, OPSTR_READ_EXTERNAL_STORAGE, OPSTR_WRITE_EXTERNAL_STORAGE, null, OPSTR_GET_ACCOUNTS, null, }; /** * This provides a simple name for each operation to be used * in debug output. */ 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", "TAKE_MEDIA_BUTTONS", "TAKE_AUDIO_FOCUS", "AUDIO_MASTER_VOLUME", "AUDIO_VOICE_VOLUME", "AUDIO_RING_VOLUME", "AUDIO_MEDIA_VOLUME", "AUDIO_ALARM_VOLUME", "AUDIO_NOTIFICATION_VOLUME", "AUDIO_BLUETOOTH_VOLUME", "WAKE_LOCK", "MONITOR_LOCATION", "MONITOR_HIGH_POWER_LOCATION", "GET_USAGE_STATS", "MUTE_MICROPHONE", "TOAST_WINDOW", "PROJECT_MEDIA", "ACTIVATE_VPN", "WRITE_WALLPAPER", "ASSIST_STRUCTURE", "ASSIST_SCREENSHOT", "OP_READ_PHONE_STATE", "ADD_VOICEMAIL", "USE_SIP", "PROCESS_OUTGOING_CALLS", "USE_FINGERPRINT", "BODY_SENSORS", "READ_CELL_BROADCASTS", "MOCK_LOCATION", "READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE", "TURN_ON_SCREEN", "GET_ACCOUNTS", "RUN_IN_BACKGROUND", }; /** * This optionally maps a permission to an operation. If there * is no permission associated with an operation, it is 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 }; /** * Specifies whether an Op should be restricted by a user restriction. * Each Op should be filled with a restriction string from UserManager or * null to specify it is not affected by any user restriction. */ private static String[] sOpRestrictions = new String[] { UserManager.DISALLOW_SHARE_LOCATION, //COARSE_LOCATION UserManager.DISALLOW_SHARE_LOCATION, //FINE_LOCATION UserManager.DISALLOW_SHARE_LOCATION, //GPS null, //VIBRATE null, //READ_CONTACTS null, //WRITE_CONTACTS UserManager.DISALLOW_OUTGOING_CALLS, //READ_CALL_LOG UserManager.DISALLOW_OUTGOING_CALLS, //WRITE_CALL_LOG null, //READ_CALENDAR null, //WRITE_CALENDAR UserManager.DISALLOW_SHARE_LOCATION, //WIFI_SCAN null, //POST_NOTIFICATION null, //NEIGHBORING_CELLS null, //CALL_PHONE UserManager.DISALLOW_SMS, //READ_SMS UserManager.DISALLOW_SMS, //WRITE_SMS UserManager.DISALLOW_SMS, //RECEIVE_SMS null, //RECEIVE_EMERGENCY_SMS UserManager.DISALLOW_SMS, //RECEIVE_MMS null, //RECEIVE_WAP_PUSH UserManager.DISALLOW_SMS, //SEND_SMS UserManager.DISALLOW_SMS, //READ_ICC_SMS UserManager.DISALLOW_SMS, //WRITE_ICC_SMS null, //WRITE_SETTINGS UserManager.DISALLOW_CREATE_WINDOWS, //SYSTEM_ALERT_WINDOW null, //ACCESS_NOTIFICATIONS UserManager.DISALLOW_CAMERA, //CAMERA UserManager.DISALLOW_RECORD_AUDIO, //RECORD_AUDIO null, //PLAY_AUDIO null, //READ_CLIPBOARD null, //WRITE_CLIPBOARD null, //TAKE_MEDIA_BUTTONS null, //TAKE_AUDIO_FOCUS UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_MASTER_VOLUME UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_VOICE_VOLUME UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_RING_VOLUME UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_MEDIA_VOLUME UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_ALARM_VOLUME UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_NOTIFICATION_VOLUME UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_BLUETOOTH_VOLUME null, //WAKE_LOCK UserManager.DISALLOW_SHARE_LOCATION, //MONITOR_LOCATION UserManager.DISALLOW_SHARE_LOCATION, //MONITOR_HIGH_POWER_LOCATION null, //GET_USAGE_STATS UserManager.DISALLOW_UNMUTE_MICROPHONE, // MUTE_MICROPHONE UserManager.DISALLOW_CREATE_WINDOWS, // TOAST_WINDOW null, //PROJECT_MEDIA null, // ACTIVATE_VPN UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER null, // ASSIST_STRUCTURE null, // ASSIST_SCREENSHOT null, // READ_PHONE_STATE null, // ADD_VOICEMAIL null, // USE_SIP null, // PROCESS_OUTGOING_CALLS null, // USE_FINGERPRINT null, // BODY_SENSORS null, // READ_CELL_BROADCASTS null, // MOCK_LOCATION null, // READ_EXTERNAL_STORAGE null, // WRITE_EXTERNAL_STORAGE null, // TURN_ON_SCREEN null, // GET_ACCOUNTS null, // RUN_IN_BACKGROUND }; /** * This specifies whether each option should allow the system * (and system ui) to bypass the user restriction when active. */ private static boolean[] sOpAllowSystemRestrictionBypass = new boolean[] { true, //COARSE_LOCATION true, //FINE_LOCATION false, //GPS false, //VIBRATE false, //READ_CONTACTS false, //WRITE_CONTACTS false, //READ_CALL_LOG false, //WRITE_CALL_LOG false, //READ_CALENDAR false, //WRITE_CALENDAR true, //WIFI_SCAN false, //POST_NOTIFICATION false, //NEIGHBORING_CELLS false, //CALL_PHONE false, //READ_SMS false, //WRITE_SMS false, //RECEIVE_SMS false, //RECEIVE_EMERGECY_SMS false, //RECEIVE_MMS false, //RECEIVE_WAP_PUSH false, //SEND_SMS false, //READ_ICC_SMS false, //WRITE_ICC_SMS false, //WRITE_SETTINGS true, //SYSTEM_ALERT_WINDOW false, //ACCESS_NOTIFICATIONS false, //CAMERA false, //RECORD_AUDIO false, //PLAY_AUDIO false, //READ_CLIPBOARD false, //WRITE_CLIPBOARD false, //TAKE_MEDIA_BUTTONS false, //TAKE_AUDIO_FOCUS false, //AUDIO_MASTER_VOLUME false, //AUDIO_VOICE_VOLUME false, //AUDIO_RING_VOLUME false, //AUDIO_MEDIA_VOLUME false, //AUDIO_ALARM_VOLUME false, //AUDIO_NOTIFICATION_VOLUME false, //AUDIO_BLUETOOTH_VOLUME false, //WAKE_LOCK false, //MONITOR_LOCATION false, //MONITOR_HIGH_POWER_LOCATION false, //GET_USAGE_STATS false, //MUTE_MICROPHONE true, //TOAST_WINDOW false, //PROJECT_MEDIA false, //ACTIVATE_VPN false, //WALLPAPER false, //ASSIST_STRUCTURE false, //ASSIST_SCREENSHOT false, //READ_PHONE_STATE false, //ADD_VOICEMAIL false, // USE_SIP false, // PROCESS_OUTGOING_CALLS false, // USE_FINGERPRINT false, // BODY_SENSORS false, // READ_CELL_BROADCASTS false, // MOCK_LOCATION false, // READ_EXTERNAL_STORAGE false, // WRITE_EXTERNAL_STORAGE false, // TURN_ON_SCREEN false, // GET_ACCOUNTS false, // RUN_IN_BACKGROUND }; /** * This specifies the default mode for each operation. */ private static int[] sOpDefaultMode = new int[] { AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_IGNORED, // OP_WRITE_SMS AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_DEFAULT, // OP_WRITE_SETTINGS AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_DEFAULT, // OP_GET_USAGE_STATS AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ERRORED, // OP_MOCK_LOCATION AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, // OP_RUN_IN_BACKGROUND }; /** * This specifies whether each option is allowed to be reset * when resetting all app preferences. Disable reset for * app ops that are under strong control of some part of the * system (such as OP_WRITE_SMS, which should be allowed only * for whichever app is selected as the current SMS app). */ private static boolean[] sOpDisableReset = new boolean[] { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, // OP_WRITE_SMS false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, }; /** * Mapping from an app op name to the app op code. */ private static HashMap sOpStrToOp = new HashMap<>(); /** * Mapping from a permission to the corresponding app op. */ private static HashMap sRuntimePermToOp = new HashMap<>(); static { if (sOpToSwitch.length != _NUM_OP) { throw new IllegalStateException("sOpToSwitch length " + sOpToSwitch.length + " should be " + _NUM_OP); } if (sOpToString.length != _NUM_OP) { throw new IllegalStateException("sOpToString length " + sOpToString.length + " should be " + _NUM_OP); } if (sOpNames.length != _NUM_OP) { throw new IllegalStateException("sOpNames length " + sOpNames.length + " should be " + _NUM_OP); } if (sOpPerms.length != _NUM_OP) { throw new IllegalStateException("sOpPerms length " + sOpPerms.length + " should be " + _NUM_OP); } if (sOpDefaultMode.length != _NUM_OP) { throw new IllegalStateException("sOpDefaultMode length " + sOpDefaultMode.length + " should be " + _NUM_OP); } if (sOpDisableReset.length != _NUM_OP) { throw new IllegalStateException("sOpDisableReset length " + sOpDisableReset.length + " should be " + _NUM_OP); } if (sOpRestrictions.length != _NUM_OP) { throw new IllegalStateException("sOpRestrictions length " + sOpRestrictions.length + " should be " + _NUM_OP); } if (sOpAllowSystemRestrictionBypass.length != _NUM_OP) { throw new IllegalStateException("sOpAllowSYstemRestrictionsBypass length " + sOpRestrictions.length + " should be " + _NUM_OP); } for (int i=0; i<_NUM_OP; i++) { if (sOpToString[i] != null) { sOpStrToOp.put(sOpToString[i], i); } } for (int op : RUNTIME_PERMISSIONS_OPS) { if (sOpPerms[op] != null) { sRuntimePermToOp.put(sOpPerms[op], op); } } } /** * Retrieve the op switch that controls the given operation. * @hide */ public static int opToSwitch(int op) { return sOpToSwitch[op]; } /** * Retrieve a non-localized name for the operation, for debugging output. * @hide */ public static String opToName(int op) { if (op == OP_NONE) return "NONE"; return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")"); } /** * @hide */ public static int strDebugOpToOp(String op) { for (int i=0; i mEntries; public PackageOps(String packageName, int uid, List entries) { mPackageName = packageName; mUid = uid; mEntries = entries; } public String getPackageName() { return mPackageName; } public int getUid() { return mUid; } public List getOps() { return mEntries; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mPackageName); dest.writeInt(mUid); dest.writeInt(mEntries.size()); for (int i=0; i(); final int N = source.readInt(); for (int i=0; i CREATOR = new Creator() { @Override public PackageOps createFromParcel(Parcel source) { return new PackageOps(source); } @Override public PackageOps[] newArray(int size) { return new PackageOps[size]; } }; } /** * Class holding the information about one unique operation of an application. * @hide */ public static class OpEntry implements Parcelable { private final int mOp; private final int mMode; private final long mTime; private final long mRejectTime; private final int mDuration; private final int mProxyUid; private final String mProxyPackageName; public OpEntry(int op, int mode, long time, long rejectTime, int duration, int proxyUid, String proxyPackage) { mOp = op; mMode = mode; mTime = time; mRejectTime = rejectTime; mDuration = duration; mProxyUid = proxyUid; mProxyPackageName = proxyPackage; } public int getOp() { return mOp; } public int getMode() { return mMode; } public long getTime() { return mTime; } public long getRejectTime() { return mRejectTime; } public boolean isRunning() { return mDuration == -1; } public int getDuration() { return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration; } public int getProxyUid() { return mProxyUid; } public String getProxyPackageName() { return mProxyPackageName; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mOp); dest.writeInt(mMode); dest.writeLong(mTime); dest.writeLong(mRejectTime); dest.writeInt(mDuration); dest.writeInt(mProxyUid); dest.writeString(mProxyPackageName); } OpEntry(Parcel source) { mOp = source.readInt(); mMode = source.readInt(); mTime = source.readLong(); mRejectTime = source.readLong(); mDuration = source.readInt(); mProxyUid = source.readInt(); mProxyPackageName = source.readString(); } public static final Creator CREATOR = new Creator() { @Override public OpEntry createFromParcel(Parcel source) { return new OpEntry(source); } @Override public OpEntry[] newArray(int size) { return new OpEntry[size]; } }; } /** * Callback for notification of changes to operation state. */ public interface OnOpChangedListener { public void onOpChanged(String op, String packageName); } /** * Callback for notification of changes to operation state. * This allows you to see the raw op codes instead of strings. * @hide */ public static class OnOpChangedInternalListener implements OnOpChangedListener { public void onOpChanged(String op, String packageName) { } public void onOpChanged(int op, String packageName) { } } AppOpsManager(Context context, IAppOpsService service) { mContext = context; mService = service; } /** * Retrieve current operation state for all applications. * * @param ops The set of operations you are interested in, or null if you want all of them. * @hide */ public List getPackagesForOps(int[] ops) { try { return mService.getPackagesForOps(ops); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Retrieve current operation state for one application. * * @param uid The uid of the application of interest. * @param packageName The name of the application of interest. * @param ops The set of operations you are interested in, or null if you want all of them. * @hide */ public List getOpsForPackage(int uid, String packageName, int[] ops) { try { return mService.getOpsForPackage(uid, packageName, ops); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Sets given app op in the specified mode for app ops in the UID. * This applies to all apps currently in the UID or installed in * this UID in the future. * * @param code The app op. * @param uid The UID for which to set the app. * @param mode The app op mode to set. * @hide */ public void setUidMode(int code, int uid, int mode) { try { mService.setUidMode(code, uid, mode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Sets given app op in the specified mode for app ops in the UID. * This applies to all apps currently in the UID or installed in * this UID in the future. * * @param appOp The app op. * @param uid The UID for which to set the app. * @param mode The app op mode to set. * @hide */ @SystemApi public void setUidMode(String appOp, int uid, int mode) { try { mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** @hide */ public void setUserRestriction(int code, boolean restricted, IBinder token) { setUserRestriction(code, restricted, token, /*exceptionPackages*/null); } /** @hide */ public void setUserRestriction(int code, boolean restricted, IBinder token, String[] exceptionPackages) { setUserRestrictionForUser(code, restricted, token, exceptionPackages, mContext.getUserId()); } /** @hide */ public void setUserRestrictionForUser(int code, boolean restricted, IBinder token, String[] exceptionPackages, int userId) { try { mService.setUserRestriction(code, restricted, token, userId, exceptionPackages); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** @hide */ public void setMode(int code, int uid, String packageName, int mode) { try { mService.setMode(code, uid, packageName, mode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Set a non-persisted restriction on an audio operation at a stream-level. * Restrictions are temporary additional constraints imposed on top of the persisted rules * defined by {@link #setMode}. * * @param code The operation to restrict. * @param usage The {@link android.media.AudioAttributes} usage value. * @param mode The restriction mode (MODE_IGNORED,MODE_ERRORED) or MODE_ALLOWED to unrestrict. * @param exceptionPackages Optional list of packages to exclude from the restriction. * @hide */ public void setRestriction(int code, @AttributeUsage int usage, int mode, String[] exceptionPackages) { try { final int uid = Binder.getCallingUid(); mService.setAudioRestriction(code, usage, uid, mode, exceptionPackages); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** @hide */ public void resetAllModes() { try { mService.resetAllModes(UserHandle.myUserId(), null); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Gets the app op name associated with a given permission. * The app op name is one of the public constants defined * in this class such as {@link #OPSTR_COARSE_LOCATION}. * This API is intended to be used for mapping runtime * permissions to the corresponding app op. * * @param permission The permission. * @return The app op associated with the permission or null. */ public static String permissionToOp(String permission) { final Integer opCode = sRuntimePermToOp.get(permission); if (opCode == null) { return null; } return sOpToString[opCode]; } /** * Monitor for changes to the operating mode for the given op in the given app package. * @param op The operation to monitor, one of OPSTR_*. * @param packageName The name of the application to monitor. * @param callback Where to report changes. */ public void startWatchingMode(String op, String packageName, final OnOpChangedListener callback) { startWatchingMode(strOpToOp(op), packageName, callback); } /** * Monitor for changes to the operating mode for the given op in the given app package. * @param op The operation to monitor, one of OP_*. * @param packageName The name of the application to monitor. * @param callback Where to report changes. * @hide */ public void startWatchingMode(int op, String packageName, final OnOpChangedListener callback) { synchronized (mModeWatchers) { IAppOpsCallback cb = mModeWatchers.get(callback); if (cb == null) { cb = new IAppOpsCallback.Stub() { public void opChanged(int op, int uid, String packageName) { if (callback instanceof OnOpChangedInternalListener) { ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName); } if (sOpToString[op] != null) { callback.onOpChanged(sOpToString[op], packageName); } } }; mModeWatchers.put(callback, cb); } try { mService.startWatchingMode(op, packageName, cb); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } /** * Stop monitoring that was previously started with {@link #startWatchingMode}. All * monitoring associated with this callback will be removed. */ public void stopWatchingMode(OnOpChangedListener callback) { synchronized (mModeWatchers) { IAppOpsCallback cb = mModeWatchers.get(callback); if (cb != null) { try { mService.stopWatchingMode(cb); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } } private String buildSecurityExceptionMsg(int op, int uid, String packageName) { return packageName + " from uid " + uid + " not allowed to perform " + sOpNames[op]; } /** * {@hide} */ public static int strOpToOp(String op) { Integer val = sOpStrToOp.get(op); if (val == null) { throw new IllegalArgumentException("Unknown operation string: " + op); } return val; } /** * Do a quick check for whether an application might be able to perform an operation. * This is not a security check; you must use {@link #noteOp(String, int, String)} * or {@link #startOp(String, int, String)} for your actual security checks, which also * ensure that the given uid and package name are consistent. This function can just be * used for a quick check to see if an operation has been disabled for the application, * as an early reject of some work. This does not modify the time stamp or other data * about the operation. * @param op The operation to check. One of the OPSTR_* constants. * @param uid The user id of the application attempting to perform the operation. * @param packageName The name of the application attempting to perform the operation. * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without * causing the app to crash). * @throws SecurityException If the app has been configured to crash on this op. */ public int checkOp(String op, int uid, String packageName) { return checkOp(strOpToOp(op), uid, packageName); } /** * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it * returns {@link #MODE_ERRORED}. */ public int checkOpNoThrow(String op, int uid, String packageName) { return checkOpNoThrow(strOpToOp(op), uid, packageName); } /** * Make note of an application performing an operation. Note that you must pass * in both the uid and name of the application to be checked; this function will verify * that these two match, and if not, return {@link #MODE_IGNORED}. If this call * succeeds, the last execution time of the operation for this app will be updated to * the current time. * @param op The operation to note. One of the OPSTR_* constants. * @param uid The user id of the application attempting to perform the operation. * @param packageName The name of the application attempting to perform the operation. * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without * causing the app to crash). * @throws SecurityException If the app has been configured to crash on this op. */ public int noteOp(String op, int uid, String packageName) { return noteOp(strOpToOp(op), uid, packageName); } /** * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it * returns {@link #MODE_ERRORED}. */ public int noteOpNoThrow(String op, int uid, String packageName) { return noteOpNoThrow(strOpToOp(op), uid, packageName); } /** * Make note of an application performing an operation on behalf of another * application when handling an IPC. Note that you must pass the package name * of the application that is being proxied while its UID will be inferred from * the IPC state; this function will verify that the calling uid and proxied * package name match, and if not, return {@link #MODE_IGNORED}. If this call * succeeds, the last execution time of the operation for the proxied app and * your app will be updated to the current time. * @param op The operation to note. One of the OPSTR_* constants. * @param proxiedPackageName The name of the application calling into the proxy application. * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without * causing the app to crash). * @throws SecurityException If the app has been configured to crash on this op. */ public int noteProxyOp(String op, String proxiedPackageName) { return noteProxyOp(strOpToOp(op), proxiedPackageName); } /** * Like {@link #noteProxyOp(String, String)} but instead * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}. */ public int noteProxyOpNoThrow(String op, String proxiedPackageName) { return noteProxyOpNoThrow(strOpToOp(op), proxiedPackageName); } /** * Report that an application has started executing a long-running operation. Note that you * must pass in both the uid and name of the application to be checked; this function will * verify that these two match, and if not, return {@link #MODE_IGNORED}. If this call * succeeds, the last execution time of the operation for this app will be updated to * the current time and the operation will be marked as "running". In this case you must * later call {@link #finishOp(String, int, String)} to report when the application is no * longer performing the operation. * @param op The operation to start. One of the OPSTR_* constants. * @param uid The user id of the application attempting to perform the operation. * @param packageName The name of the application attempting to perform the operation. * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without * causing the app to crash). * @throws SecurityException If the app has been configured to crash on this op. */ public int startOp(String op, int uid, String packageName) { return startOp(strOpToOp(op), uid, packageName); } /** * Like {@link #startOp} but instead of throwing a {@link SecurityException} it * returns {@link #MODE_ERRORED}. */ public int startOpNoThrow(String op, int uid, String packageName) { return startOpNoThrow(strOpToOp(op), uid, packageName); } /** * Report that an application is no longer performing an operation that had previously * been started with {@link #startOp(String, int, String)}. There is no validation of input * or result; the parameters supplied here must be the exact same ones previously passed * in when starting the operation. */ public void finishOp(String op, int uid, String packageName) { finishOp(strOpToOp(op), uid, packageName); } /** * Do a quick check for whether an application might be able to perform an operation. * This is not a security check; you must use {@link #noteOp(int, int, String)} * or {@link #startOp(int, int, String)} for your actual security checks, which also * ensure that the given uid and package name are consistent. This function can just be * used for a quick check to see if an operation has been disabled for the application, * as an early reject of some work. This does not modify the time stamp or other data * about the operation. * @param op The operation to check. One of the OP_* constants. * @param uid The user id of the application attempting to perform the operation. * @param packageName The name of the application attempting to perform the operation. * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without * causing the app to crash). * @throws SecurityException If the app has been configured to crash on this op. * @hide */ 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(); } } /** * 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); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Do a quick check to validate if a package name belongs to a UID. * * @throws SecurityException if the package name doesn't belong to the given * UID, or if ownership cannot be verified. */ public void checkPackage(int uid, String packageName) { try { if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) { throw new SecurityException( "Package " + packageName + " does not belong to " + uid); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Like {@link #checkOp} but at a stream-level for audio operations. * @hide */ public int checkAudioOp(int op, int stream, int uid, String packageName) { try { final int mode = mService.checkAudioOperation(op, stream, uid, packageName); if (mode == MODE_ERRORED) { throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); } return mode; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Like {@link #checkAudioOp} but instead of throwing a {@link SecurityException} it * returns {@link #MODE_ERRORED}. * @hide */ public int checkAudioOpNoThrow(int op, int stream, int uid, String packageName) { try { return mService.checkAudioOperation(op, stream, uid, packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Make note of an application performing an operation. Note that you must pass * in both the uid and name of the application to be checked; this function will verify * that these two match, and if not, return {@link #MODE_IGNORED}. If this call * succeeds, the last execution time of the operation for this app will be updated to * the current time. * @param op The operation to note. One of the OP_* constants. * @param uid The user id of the application attempting to perform the operation. * @param packageName The name of the application attempting to perform the operation. * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without * causing the app to crash). * @throws SecurityException If the app has been configured to crash on this op. * @hide */ public int noteOp(int op, int uid, String packageName) { try { int mode = mService.noteOperation(op, uid, packageName); if (mode == MODE_ERRORED) { throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); } return mode; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Make note of an application performing an operation on behalf of another * application when handling an IPC. Note that you must pass the package name * of the application that is being proxied while its UID will be inferred from * the IPC state; this function will verify that the calling uid and proxied * package name match, and if not, return {@link #MODE_IGNORED}. If this call * succeeds, the last execution time of the operation for the proxied app and * your app will be updated to the current time. * @param op The operation to note. One of the OPSTR_* constants. * @param proxiedPackageName The name of the application calling into the proxy application. * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without * causing the app to crash). * @throws SecurityException If the proxy or proxied app has been configured to * crash on this op. * * @hide */ public int noteProxyOp(int op, String proxiedPackageName) { int mode = noteProxyOpNoThrow(op, proxiedPackageName); if (mode == MODE_ERRORED) { throw new SecurityException("Proxy package " + mContext.getOpPackageName() + " from uid " + Process.myUid() + " or calling package " + proxiedPackageName + " from uid " + Binder.getCallingUid() + " not allowed to perform " + sOpNames[op]); } return mode; } /** * Like {@link #noteProxyOp(int, String)} but instead * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}. * @hide */ public int noteProxyOpNoThrow(int op, String proxiedPackageName) { try { return mService.noteProxyOperation(op, mContext.getOpPackageName(), Binder.getCallingUid(), proxiedPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it * returns {@link #MODE_ERRORED}. * @hide */ public int noteOpNoThrow(int op, int uid, String packageName) { try { return mService.noteOperation(op, uid, packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** @hide */ public int noteOp(int op) { return noteOp(op, Process.myUid(), mContext.getOpPackageName()); } /** @hide */ public static IBinder getToken(IAppOpsService service) { synchronized (AppOpsManager.class) { if (sToken != null) { return sToken; } try { sToken = service.getToken(new Binder()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return sToken; } } /** * Report that an application has started executing a long-running operation. Note that you * must pass in both the uid and name of the application to be checked; this function will * verify that these two match, and if not, return {@link #MODE_IGNORED}. If this call * succeeds, the last execution time of the operation for this app will be updated to * the current time and the operation will be marked as "running". In this case you must * later call {@link #finishOp(int, int, String)} to report when the application is no * longer performing the operation. * @param op The operation to start. One of the OP_* constants. * @param uid The user id of the application attempting to perform the operation. * @param packageName The name of the application attempting to perform the operation. * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without * causing the app to crash). * @throws SecurityException If the app has been configured to crash on this op. * @hide */ public int startOp(int op, int uid, String packageName) { try { int mode = mService.startOperation(getToken(mService), op, uid, packageName); if (mode == MODE_ERRORED) { throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); } return mode; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Like {@link #startOp} but instead of throwing a {@link SecurityException} it * returns {@link #MODE_ERRORED}. * @hide */ public int startOpNoThrow(int op, int uid, String packageName) { try { return mService.startOperation(getToken(mService), op, uid, packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** @hide */ public int startOp(int op) { return startOp(op, Process.myUid(), mContext.getOpPackageName()); } /** * Report that an application is no longer performing an operation that had previously * been started with {@link #startOp(int, int, String)}. There is no validation of input * or result; the parameters supplied here must be the exact same ones previously passed * in when starting the operation. * @hide */ public void finishOp(int op, int uid, String packageName) { try { mService.finishOperation(getToken(mService), op, uid, packageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** @hide */ public void finishOp(int op) { finishOp(op, Process.myUid(), mContext.getOpPackageName()); } }