Android AppOpsService

Application Operations Service

Posted by LXG on January 11, 2021

Android原生权限管理AppOps-简书

App Ops

简介

在 Android 系统中存在一个叫做 “appops” 的系统服务,该服务定义了一系列的“应用操作”(application operation, op)。其中部分“应用操作”与“权限”对应(如 OP_CAMERA 与“相机权限”),其余则对应单独的功能(如 OP_READ_CLIPBOARD 与读取剪贴板,但并不存在“读取剪贴板权限”)。

原生 Android 系统使用 appops 来追踪权限使用,appops 也部分被用于权限控制。每个应用都有自己的 “appops” 设置,当应用需要执行某些操作时,系统在检查权限的同时也会检查 “appops” 设置。如果没有授予权限,应用在执行操作时将会收到错误。但不同的是,如果 “appops” 设为ignore,应用不会收到错误只会收到空白数据。

架构

app_ops_service

AppOpsManager


@SystemService(Context.APP_OPS_SERVICE)
public class AppOpsManager {

    /**
     * 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
     * <em>silently fail</em> (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;
    
        /**
     * Special mode that means "allow only when app is in foreground."  This is <b>not</b>
     * returned from {@link #unsafeCheckOp}, {@link #noteOp}, {@link #startOp}.  Rather,
     * {@link #unsafeCheckOp} will always return {@link #MODE_ALLOWED} (because it is always
     * possible for it to be ultimately allowed, depending on the app's background state),
     * and {@link #noteOp} and {@link #startOp} will return {@link #MODE_ALLOWED} when the app
     * being checked is currently in the foreground, otherwise {@link #MODE_IGNORED}.
     *
     * <p>The only place you will this normally see this value is through
     * {@link #unsafeCheckOpRaw}, which returns the actual raw mode of the op.  Note that because
     * you can't know the current state of the app being checked (and it can change at any
     * point), you can only treat the result here as an indication that it will vary between
     * {@link #MODE_ALLOWED} and {@link #MODE_IGNORED} depending on changes in the background
     * state of the app.  You thus must always use {@link #noteOp} or {@link #startOp} to do
     * the actual check for access to the op.</p>
     */
    public static final int MODE_FOREGROUND = 4;
    
        /**
     * This optionally maps a permission to an operation.  If there
     * is no permission associated with an operation, it is null.
     */
    @UnsupportedAppUsage
    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,
            Manifest.permission.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,
            null, // no permission for OP_QUERY_ALL_PACKAGES
            Manifest.permission.MANAGE_EXTERNAL_STORAGE,
            android.Manifest.permission.INTERACT_ACROSS_PROFILES,
            null, // no permission for OP_ACTIVATE_PLATFORM_VPN
            android.Manifest.permission.LOADER_USAGE_STATS,
            null, // deprecated operation
            null, // no permission for OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
            null, // no permission for OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
            null, // no permission for OP_NO_ISOLATED_STORAGE
    };
    
}

enums.proto


// AppOpsManager.java - operation ids for logging
enum AppOpEnum {
    APP_OP_NONE = -1;
    APP_OP_COARSE_LOCATION = 0;
    APP_OP_FINE_LOCATION = 1;
    APP_OP_GPS = 2;
    APP_OP_VIBRATE = 3;
    APP_OP_READ_CONTACTS = 4;
    APP_OP_WRITE_CONTACTS = 5;
    APP_OP_READ_CALL_LOG = 6;
    APP_OP_WRITE_CALL_LOG = 7;
    APP_OP_READ_CALENDAR = 8;
    APP_OP_WRITE_CALENDAR = 9;
    APP_OP_WIFI_SCAN = 10;
    APP_OP_POST_NOTIFICATION = 11;
    APP_OP_NEIGHBORING_CELLS = 12;
    APP_OP_CALL_PHONE = 13;
    APP_OP_READ_SMS = 14;
    APP_OP_WRITE_SMS = 15;
    APP_OP_RECEIVE_SMS = 16;
    APP_OP_RECEIVE_EMERGENCY_SMS = 17;
    APP_OP_RECEIVE_MMS = 18;
    APP_OP_RECEIVE_WAP_PUSH = 19;
    APP_OP_SEND_SMS = 20;
    APP_OP_READ_ICC_SMS = 21;
    APP_OP_WRITE_ICC_SMS = 22;
    APP_OP_WRITE_SETTINGS = 23;
    APP_OP_SYSTEM_ALERT_WINDOW = 24;
    APP_OP_ACCESS_NOTIFICATIONS = 25;
    APP_OP_CAMERA = 26;
    APP_OP_RECORD_AUDIO = 27;
    APP_OP_PLAY_AUDIO = 28;
    APP_OP_READ_CLIPBOARD = 29;
    APP_OP_WRITE_CLIPBOARD = 30;
    APP_OP_TAKE_MEDIA_BUTTONS = 31;
    APP_OP_TAKE_AUDIO_FOCUS = 32;
    APP_OP_AUDIO_MASTER_VOLUME = 33;
    APP_OP_AUDIO_VOICE_VOLUME = 34;
    APP_OP_AUDIO_RING_VOLUME = 35;
    APP_OP_AUDIO_MEDIA_VOLUME = 36;
    APP_OP_AUDIO_ALARM_VOLUME = 37;
    APP_OP_AUDIO_NOTIFICATION_VOLUME = 38;
    APP_OP_AUDIO_BLUETOOTH_VOLUME = 39;
    APP_OP_WAKE_LOCK = 40;
    APP_OP_MONITOR_LOCATION = 41;
    APP_OP_MONITOR_HIGH_POWER_LOCATION = 42;
    APP_OP_GET_USAGE_STATS = 43;
    APP_OP_MUTE_MICROPHONE = 44;
    APP_OP_TOAST_WINDOW = 45;
    APP_OP_PROJECT_MEDIA = 46;
    APP_OP_ACTIVATE_VPN = 47;
    APP_OP_WRITE_WALLPAPER = 48;
    APP_OP_ASSIST_STRUCTURE = 49;
    APP_OP_ASSIST_SCREENSHOT = 50;
    APP_OP_READ_PHONE_STATE = 51;
    APP_OP_ADD_VOICEMAIL = 52;
    APP_OP_USE_SIP = 53;
    APP_OP_PROCESS_OUTGOING_CALLS = 54;
    APP_OP_USE_FINGERPRINT = 55;
    APP_OP_BODY_SENSORS = 56;
    APP_OP_READ_CELL_BROADCASTS = 57;
    APP_OP_MOCK_LOCATION = 58;
    APP_OP_READ_EXTERNAL_STORAGE = 59;
    APP_OP_WRITE_EXTERNAL_STORAGE = 60;
    APP_OP_TURN_SCREEN_ON = 61;
    APP_OP_GET_ACCOUNTS = 62;
    APP_OP_RUN_IN_BACKGROUND = 63;
    APP_OP_AUDIO_ACCESSIBILITY_VOLUME = 64;
    APP_OP_READ_PHONE_NUMBERS = 65;
    APP_OP_REQUEST_INSTALL_PACKAGES = 66;
    APP_OP_PICTURE_IN_PICTURE = 67;
    APP_OP_INSTANT_APP_START_FOREGROUND = 68;
    APP_OP_ANSWER_PHONE_CALLS = 69;
    APP_OP_RUN_ANY_IN_BACKGROUND = 70;
    APP_OP_CHANGE_WIFI_STATE = 71;
    APP_OP_REQUEST_DELETE_PACKAGES = 72;
    APP_OP_BIND_ACCESSIBILITY_SERVICE = 73;
    APP_OP_ACCEPT_HANDOVER = 74;
    APP_OP_MANAGE_IPSEC_TUNNELS = 75;
    APP_OP_START_FOREGROUND = 76;
    APP_OP_BLUETOOTH_SCAN = 77;
    APP_OP_USE_BIOMETRIC = 78;
    APP_OP_ACTIVITY_RECOGNITION = 79;
    APP_OP_SMS_FINANCIAL_TRANSACTIONS = 80;
    APP_OP_READ_MEDIA_AUDIO = 81;
    APP_OP_WRITE_MEDIA_AUDIO = 82;
    APP_OP_READ_MEDIA_VIDEO = 83;
    APP_OP_WRITE_MEDIA_VIDEO = 84;
    APP_OP_READ_MEDIA_IMAGES = 85;
    APP_OP_WRITE_MEDIA_IMAGES = 86;
    APP_OP_LEGACY_STORAGE = 87;
    APP_OP_ACCESS_ACCESSIBILITY = 88;
    APP_OP_READ_DEVICE_IDENTIFIERS = 89;
    APP_OP_ACCESS_MEDIA_LOCATION = 90;
    APP_OP_QUERY_ALL_PACKAGES = 91;
    APP_OP_MANAGE_EXTERNAL_STORAGE = 92;
    APP_OP_INTERACT_ACROSS_PROFILES = 93;
    APP_OP_ACTIVATE_PLATFORM_VPN = 94;
    APP_OP_LOADER_USAGE_STATS = 95;
    APP_OP_DEPRECATED_1 = 96 [deprecated = true];
    APP_OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97;
    APP_OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98;
    APP_OP_NO_ISOLATED_STORAGE = 99;
}

AppOpsService


public class AppOpsService extends IAppOpsService.Stub {
    static final String TAG = "AppOps";

    public AppOpsService(File storagePath, Handler handler, Context context) {
        // data/system
        mFile = new AtomicFile(storagePath, "appops");
        readState();

    }

    @Override
    public int checkOperation(int code, int uid, String packageName) {
        return checkOperationInternal(code, uid, packageName, false /*raw*/);
    }

    private int checkOperationImpl(int code, int uid, String packageName,
                boolean raw) {
        verifyIncomingOp(code);
        String resolvedPackageName = resolvePackageName(uid, packageName);
        if (resolvedPackageName == null) {
            return AppOpsManager.MODE_IGNORED;
        }
        return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
    }

    /**
     * Get the mode of an app-op.
     *
     * @param code The code of the op
     * @param uid The uid of the package the op belongs to
     * @param packageName The package the op belongs to
     * @param raw If the raw state of eval-ed state should be checked.
     *
     * @return The mode of the op
     */
    private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
                boolean raw) {
        RestrictionBypass bypass;
        try {
            bypass = verifyAndGetBypass(uid, packageName, null);
        } catch (SecurityException e) {
            Slog.e(TAG, "checkOperation", e);
            return AppOpsManager.opToDefaultMode(code);
        }

        if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
            return AppOpsManager.MODE_IGNORED;
        }
        synchronized (this) {
            if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
                return AppOpsManager.MODE_IGNORED;
            }
            code = AppOpsManager.opToSwitch(code);
            UidState uidState = getUidStateLocked(uid, false);
            if (uidState != null && uidState.opModes != null
                    && uidState.opModes.indexOfKey(code) >= 0) {
                final int rawMode = uidState.opModes.get(code);
                return raw ? rawMode : uidState.evalMode(code, rawMode);
            }
            Op op = getOpLocked(code, uid, packageName, null, bypass, false);
            if (op == null) {
                return AppOpsManager.opToDefaultMode(code);
            }
            return raw ? op.mode : op.evalMode();
        }
    }

}

data/system/appops.xml


<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<app-ops v="1">

<uid n="10119">
<op n="87" m="1" />
</uid>

<pkg n="com.***">
<uid n="10119">
<op n="0" />
<op n="1">
<st n="1073741824001" t="1610352065086" r="1610334827892" />
<st n="1503238553601" r="1610348532835" />
</op>
<op n="2">
<st n="1073741824001" t="1610351967223" d="97899" />
<st n="1288490188801" t="1610348464947" d="304" />
<st n="1503238553601" t="1610348465251" d="84" />
</op>
<op n="10">
<st n="1073741824001" t="1610352065087" />
</op>
<op n="41">
<st n="1073741824001" t="1610351967165" r="1610334993865" d="97966" />
<st n="1288490188801" t="1610348464947" d="303" />
<st n="1503238553601" t="1610348465251" d="65" />
</op>
<op n="42">
<st n="1073741824001" t="1610351967220" d="97877" />
<st n="1288490188801" t="1610348464947" d="303" />
<st n="1503238553601" t="1610348465251" d="60" />
</op>
<op n="71">
<st n="1073741824001" t="1610352061960" />
</op>
</uid>
</pkg>

dumpsys appops


qssi:/ $ dumpsys appops -h
AppOps service (appops) dump options:
  -h
    Print this help text.
  --op [OP]
    Limit output to data associated with the given app op code.
  --mode [MODE]
    Limit output to data associated with the given app op mode.
  --package [PACKAGE]
    Limit output to data associated with the given package name.
  --attributionTag [attributionTag]
    Limit output to data associated with the given attribution tag.
  --watchers
    Only output the watcher sections.


qssi:/ $ dumpsys appops
Current AppOps Service state:
  Settings:
    top_state_settle_time=+5s0ms
    fg_service_state_settle_time=+5s0ms
    bg_state_settle_time=+1s0ms

  Op mode watchers:
    Op COARSE_LOCATION:
      #0: ModeCallback{3f47b05 watchinguid=-1 flags=0x0 op=READ_SMS from uid=1000 pid=1738}
      #1: ModeCallback{75d29da watchinguid=-1 flags=0x1 op=COARSE_LOCATION from uid=1000 pid=1738}
    ---------------------------------------
  Package mode watchers:
    Pkg com.android.mms.service:
      #0: ModeCallback{6204ca3 watchinguid=-1 flags=0x0 op=PLAY_AUDIO from uid=1041 pid=1381}
    Pkg com.android.location.fused:
      #0: ModeCallback{6ff9575 watchinguid=-1 flags=0x0 op=PLAY_AUDIO from uid=1041 pid=1381}
      #1: ModeCallback{e19df0d watchinguid=-1 flags=0x0 op=PLAY_AUDIO from uid=1041 pid=1381}
  All op mode watchers:
    e2671a: ModeCallback{3ec024b watchinguid=-1 flags=0x0 op=GET_ACCOUNTS from uid=1000 pid=1738}
    2aa0403: ModeCallback{ceecf80 watchinguid=-1 flags=0x0 op=RUN_ANY_IN_BACKGROUND from uid=1000 pid=1738}
    2d295a4: ModeCallback{e19df0d watchinguid=-1 flags=0x0 op=PLAY_AUDIO from uid=1041 pid=1381}
    42e4785: ModeCallback{75d29da watchinguid=-1 flags=0x1 op=COARSE_LOCATION from uid=1000 pid=1738}
    50d04ac: ModeCallback{6ff9575 watchinguid=-1 flags=0x0 op=PLAY_AUDIO from uid=1041 pid=1381}
    576c67c: ModeCallback{3f47b05 watchinguid=-1 flags=0x0 op=READ_SMS from uid=1000 pid=1738}
    7a690c1: ModeCallback{84ca066 watchinguid=-1 flags=0x0 op=SYSTEM_ALERT_WINDOW from uid=1000 pid=1738}
    95a83d2: ModeCallback{6204ca3 watchinguid=-1 flags=0x0 op=PLAY_AUDIO from uid=1041 pid=1381}
    b696edb: ModeCallback{40d1d78 watchinguid=-1 flags=0x0 op=READ_EXTERNAL_STORAGE from uid=u0a158 pid=3444}
    cb2bf24: ModeCallback{cf02442 watchinguid=-1 flags=0x0 op=RUN_IN_BACKGROUND from uid=1000 pid=1738}
  All op active watchers:
    98a1797 ->
        [COARSE_LOCATION, FINE_LOCATION, SYSTEM_ALERT_WINDOW, CAMERA, RECORD_AUDIO]
        ActiveCallback{96892e4 watchinguid=-1 from uid=u0a138 pid=2375}
    a57bc53 ->
        [CAMERA]
        ActiveCallback{ea0334d watchinguid=-1 from uid=1000 pid=1738}
    e7a07d5 ->
        [CAMERA]
        ActiveCallback{4657e02 watchinguid=-1 from uid=u0a158 pid=3444}
  All op noted watchers:
    8c63d84 ->
        [COARSE_LOCATION, FINE_LOCATION, SYSTEM_ALERT_WINDOW, CAMERA, RECORD_AUDIO]
        NotedCallback{364842a watchinguid=-1 from uid=u0a138 pid=2375}

  Uid u0a119:
    state=bg
    capability=---
    appWidgetVisible=false
      LEGACY_STORAGE: mode=ignore
    Package com.sunmi.baseservice:
      COARSE_LOCATION (allow): 
      FINE_LOCATION (allow / switch COARSE_LOCATION=allow): 
        null=[
          Access: [fg-s] 2021-01-11 16:01:05.086 (-1h5m27s679ms)
          Reject: [fg-s]2021-01-11 11:13:47.892 (-5h52m44s873ms)
          Reject: [cch-s]2021-01-11 15:02:12.835 (-2h4m19s930ms)
        ]
      GPS (allow / switch COARSE_LOCATION=allow): 
        null=[
          Access: [fg-s] 2021-01-11 15:59:27.223 (-1h7m5s542ms) duration=+1m37s899ms
          Access: [bg-s] 2021-01-11 15:01:04.947 (-2h5m27s818ms) duration=+304ms
          Access: [cch-s] 2021-01-11 15:01:05.251 (-2h5m27s514ms) duration=+84ms
        ]
      WIFI_SCAN (allow / switch COARSE_LOCATION=allow): 
        null=[
          Access: [fg-s] 2021-01-11 16:01:05.087 (-1h5m27s678ms)
        ]
      MONITOR_LOCATION (allow / switch COARSE_LOCATION=allow): 
        null=[
          Access: [fg-s] 2021-01-11 15:59:27.165 (-1h7m5s600ms) duration=+1m37s966ms
          Reject: [fg-s]2021-01-11 11:16:33.865 (-5h49m58s900ms)
          Access: [bg-s] 2021-01-11 15:01:04.947 (-2h5m27s818ms) duration=+303ms
          Access: [cch-s] 2021-01-11 15:01:05.251 (-2h5m27s514ms) duration=+65ms
        ]
      MONITOR_HIGH_POWER_LOCATION (allow / switch COARSE_LOCATION=allow): 
        null=[
          Access: [fg-s] 2021-01-11 15:59:27.220 (-1h7m5s545ms) duration=+1m37s877ms
          Access: [bg-s] 2021-01-11 15:01:04.947 (-2h5m27s818ms) duration=+303ms
          Access: [cch-s] 2021-01-11 15:01:05.251 (-2h5m27s514ms) duration=+60ms
        ]
      CHANGE_WIFI_STATE (allow): 
        null=[
          Access: [fg-s] 2021-01-11 16:01:01.960 (-1h5m30s805ms)
        ]

appops help


127|qssi:/ $appops

AppOps service (appops) commands:
  help
    Print this help text.
  start [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> <OP> 
    Starts a given operation for a particular application.
  stop [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> <OP> 
    Stops a given operation for a particular application.
  set [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>
    Set the mode for a particular application and operation.
  get [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> [<OP>]
    Return the mode for a particular application and optional operation.
  query-op [--user <USER_ID>] <OP> [<MODE>]
    Print all packages that currently have the given op in the given mode.
  reset [--user <USER_ID>] [<PACKAGE>]
    Reset the given application or all applications to default modes.
  write-settings
    Immediately write pending changes to storage.
  read-settings
    Read the last written settings, replacing current state in RAM.
  options:
    <PACKAGE> an Android package name or its UID if prefixed by --uid
    <OP>      an AppOps operation.
    <MODE>    one of allow, ignore, deny, or default
    <USER_ID> the user id under which the package is installed. If --user is
              not specified, the current user is assumed.