blob: a11f41fbc5d05d2ce94b503e890b9e92d04fb8b6 [file] [log] [blame]
/*
* 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.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.usage.UsageStatsManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.database.DatabaseUtils;
import android.media.AudioAttributes.AttributeUsage;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongSparseArray;
import android.util.LongSparseLongArray;
import android.util.Pools;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.Immutable;
import com.android.internal.app.IAppOpsActiveCallback;
import com.android.internal.app.IAppOpsAsyncNotedCallback;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsNotedCallback;
import com.android.internal.app.IAppOpsService;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.ZygoteInit;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
import com.android.internal.util.Preconditions;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* 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.
*/
@SystemService(Context.APP_OPS_SERVICE)
public class AppOpsManager {
/**
* <p>App ops allows callers to:</p>
*
* <ul>
* <li> Note when operations are happening, and find out if they are allowed for the current
* caller.</li>
* <li> Disallow specific apps from doing specific operations.</li>
* <li> Collect all of the current information about operations that have been executed or
* are not being allowed.</li>
* <li> Monitor for changes in whether an operation is allowed.</li>
* </ul>
*
* <p>Each operation is identified by a single integer; these integers are a fixed set of
* operations, enumerated by the OP_* constants.
*
* <p></p>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;
@UnsupportedAppUsage
final IAppOpsService mService;
@GuardedBy("mModeWatchers")
private final ArrayMap<OnOpChangedListener, IAppOpsCallback> mModeWatchers =
new ArrayMap<>();
@GuardedBy("mActiveWatchers")
private final ArrayMap<OnOpActiveChangedListener, IAppOpsActiveCallback> mActiveWatchers =
new ArrayMap<>();
@GuardedBy("mNotedWatchers")
private final ArrayMap<OnOpNotedListener, IAppOpsNotedCallback> mNotedWatchers =
new ArrayMap<>();
private static final Object sLock = new Object();
/** Current {@link AppOpsCollector}. Change via {@link #setNotedAppOpsCollector} */
@GuardedBy("sLock")
private static @Nullable AppOpsCollector sNotedAppOpsCollector;
static IBinder sClientId;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "HISTORICAL_MODE_" }, value = {
HISTORICAL_MODE_DISABLED,
HISTORICAL_MODE_ENABLED_ACTIVE,
HISTORICAL_MODE_ENABLED_PASSIVE
})
public @interface HistoricalMode {}
/**
* Mode in which app op history is completely disabled.
* @hide
*/
@TestApi
public static final int HISTORICAL_MODE_DISABLED = 0;
/**
* Mode in which app op history is enabled and app ops performed by apps would
* be tracked. This is the mode in which the feature is completely enabled.
* @hide
*/
@TestApi
public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1;
/**
* Mode in which app op history is enabled but app ops performed by apps would
* not be tracked and the only way to add ops to the history is via explicit calls
* to dedicated APIs. This mode is useful for testing to allow full control of
* the historical content.
* @hide
*/
@TestApi
public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "MODE_" }, value = {
MODE_ALLOWED,
MODE_IGNORED,
MODE_ERRORED,
MODE_DEFAULT,
MODE_FOREGROUND
})
public @interface Mode {}
/**
* 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;
/**
* Flag for {@link #startWatchingMode(String, String, int, OnOpChangedListener)}:
* Also get reports if the foreground state of an op's uid changes. This only works
* when watching a particular op, not when watching a package.
*/
public static final int WATCH_FOREGROUND_CHANGES = 1 << 0;
/**
* @hide
*/
public static final String[] MODE_NAMES = new String[] {
"allow", // MODE_ALLOWED
"ignore", // MODE_IGNORED
"deny", // MODE_ERRORED
"default", // MODE_DEFAULT
"foreground", // MODE_FOREGROUND
};
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "UID_STATE_" }, value = {
UID_STATE_PERSISTENT,
UID_STATE_TOP,
UID_STATE_FOREGROUND_SERVICE_LOCATION,
UID_STATE_FOREGROUND_SERVICE,
UID_STATE_FOREGROUND,
UID_STATE_BACKGROUND,
UID_STATE_CACHED
})
public @interface UidState {}
/**
* Uid state: The UID is a foreground persistent app. The lower the UID
* state the more important the UID is for the user.
* @hide
*/
@TestApi
@SystemApi
public static final int UID_STATE_PERSISTENT = 100;
/**
* Uid state: The UID is top foreground app. The lower the UID
* state the more important the UID is for the user.
* @hide
*/
@TestApi
@SystemApi
public static final int UID_STATE_TOP = 200;
/**
* Uid state: The UID is running a foreground service of location type.
* The lower the UID state the more important the UID is for the user.
* This uid state is a counterpart to PROCESS_STATE_FOREGROUND_SERVICE_LOCATION which has been
* deprecated.
* @hide
* @deprecated
*/
@TestApi
@SystemApi
@Deprecated
public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300;
/**
* Uid state: The UID is running a foreground service. The lower the UID
* state the more important the UID is for the user.
* @hide
*/
@TestApi
@SystemApi
public static final int UID_STATE_FOREGROUND_SERVICE = 400;
/**
* Uid state: The UID is a foreground app. The lower the UID
* state the more important the UID is for the user.
* @hide
*/
@TestApi
@SystemApi
public static final int UID_STATE_FOREGROUND = 500;
/**
* The max, which is min priority, UID state for which any app op
* would be considered as performed in the foreground.
* @hide
*/
public static final int UID_STATE_MAX_LAST_NON_RESTRICTED = UID_STATE_FOREGROUND;
/**
* Uid state: The UID is a background app. The lower the UID
* state the more important the UID is for the user.
* @hide
*/
@TestApi
@SystemApi
public static final int UID_STATE_BACKGROUND = 600;
/**
* Uid state: The UID is a cached app. The lower the UID
* state the more important the UID is for the user.
* @hide
*/
@TestApi
@SystemApi
public static final int UID_STATE_CACHED = 700;
/**
* Uid state: The UID state with the highest priority.
* @hide
*/
public static final int MAX_PRIORITY_UID_STATE = UID_STATE_PERSISTENT;
/**
* Uid state: The UID state with the lowest priority.
* @hide
*/
public static final int MIN_PRIORITY_UID_STATE = UID_STATE_CACHED;
/**
* Resolves the first unrestricted state given an app op.
* @param op The op to resolve.
* @return The last restricted UID state.
*
* @hide
*/
public static int resolveFirstUnrestrictedUidState(int op) {
return UID_STATE_FOREGROUND;
}
/**
* Resolves the last restricted state given an app op.
* @param op The op to resolve.
* @return The last restricted UID state.
*
* @hide
*/
public static int resolveLastRestrictedUidState(int op) {
return UID_STATE_BACKGROUND;
}
/** @hide Note: Keep these sorted */
public static final int[] UID_STATES = {
UID_STATE_PERSISTENT,
UID_STATE_TOP,
UID_STATE_FOREGROUND_SERVICE_LOCATION,
UID_STATE_FOREGROUND_SERVICE,
UID_STATE_FOREGROUND,
UID_STATE_BACKGROUND,
UID_STATE_CACHED
};
/** @hide */
public static String getUidStateName(@UidState int uidState) {
switch (uidState) {
case UID_STATE_PERSISTENT:
return "pers";
case UID_STATE_TOP:
return "top";
case UID_STATE_FOREGROUND_SERVICE_LOCATION:
return "fgsvcl";
case UID_STATE_FOREGROUND_SERVICE:
return "fgsvc";
case UID_STATE_FOREGROUND:
return "fg";
case UID_STATE_BACKGROUND:
return "bg";
case UID_STATE_CACHED:
return "cch";
default:
return "unknown";
}
}
/**
* Flag: non proxy operations. These are operations
* performed on behalf of the app itself and not on behalf of
* another one.
*
* @hide
*/
@TestApi
@SystemApi
public static final int OP_FLAG_SELF = 0x1;
/**
* Flag: trusted proxy operations. These are operations
* performed on behalf of another app by a trusted app.
* Which is work a trusted app blames on another app.
*
* @hide
*/
@TestApi
@SystemApi
public static final int OP_FLAG_TRUSTED_PROXY = 0x2;
/**
* Flag: untrusted proxy operations. These are operations
* performed on behalf of another app by an untrusted app.
* Which is work an untrusted app blames on another app.
*
* @hide
*/
@TestApi
@SystemApi
public static final int OP_FLAG_UNTRUSTED_PROXY = 0x4;
/**
* Flag: trusted proxied operations. These are operations
* performed by a trusted other app on behalf of an app.
* Which is work an app was blamed for by a trusted app.
*
* @hide
*/
@TestApi
@SystemApi
public static final int OP_FLAG_TRUSTED_PROXIED = 0x8;
/**
* Flag: untrusted proxied operations. These are operations
* performed by an untrusted other app on behalf of an app.
* Which is work an app was blamed for by an untrusted app.
*
* @hide
*/
@TestApi
@SystemApi
public static final int OP_FLAG_UNTRUSTED_PROXIED = 0x10;
/**
* Flags: all operations. These include operations matched
* by {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}.
*
* @hide
*/
@TestApi
@SystemApi
public static final int OP_FLAGS_ALL =
OP_FLAG_SELF
| OP_FLAG_TRUSTED_PROXY
| OP_FLAG_UNTRUSTED_PROXY
| OP_FLAG_TRUSTED_PROXIED
| OP_FLAG_UNTRUSTED_PROXIED;
/**
* Flags: all trusted operations which is ones either the app did {@link #OP_FLAG_SELF},
* or it was blamed for by a trusted app {@link #OP_FLAG_TRUSTED_PROXIED}, or ones the
* app if untrusted blamed on other apps {@link #OP_FLAG_UNTRUSTED_PROXY}.
*
* @hide
*/
@SystemApi
public static final int OP_FLAGS_ALL_TRUSTED = AppOpsManager.OP_FLAG_SELF
| AppOpsManager.OP_FLAG_UNTRUSTED_PROXY
| AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "FLAG_" }, value = {
OP_FLAG_SELF,
OP_FLAG_TRUSTED_PROXY,
OP_FLAG_UNTRUSTED_PROXY,
OP_FLAG_TRUSTED_PROXIED,
OP_FLAG_UNTRUSTED_PROXIED
})
public @interface OpFlags {}
/** @hide */
public static final String getFlagName(@OpFlags int flag) {
switch (flag) {
case OP_FLAG_SELF:
return "s";
case OP_FLAG_TRUSTED_PROXY:
return "tp";
case OP_FLAG_UNTRUSTED_PROXY:
return "up";
case OP_FLAG_TRUSTED_PROXIED:
return "tpd";
case OP_FLAG_UNTRUSTED_PROXIED:
return "upd";
default:
return "unknown";
}
}
private static final int UID_STATE_OFFSET = 31;
private static final int FLAGS_MASK = 0xFFFFFFFF;
/**
* Key for a data bucket storing app op state. The bucket
* is composed of the uid state and state flags. This way
* we can query data for given uid state and a set of flags where
* the flags control which type of data to get. For example,
* one can get the ops an app did on behalf of other apps
* while in the background.
*
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
public @interface DataBucketKey {
}
/** @hide */
public static String keyToString(@DataBucketKey long key) {
final int uidState = extractUidStateFromKey(key);
final int flags = extractFlagsFromKey(key);
return "[" + getUidStateName(uidState) + "-" + flagsToString(flags) + "]";
}
/** @hide */
public static @DataBucketKey long makeKey(@UidState int uidState, @OpFlags int flags) {
return ((long) uidState << UID_STATE_OFFSET) | flags;
}
/** @hide */
public static int extractUidStateFromKey(@DataBucketKey long key) {
return (int) (key >> UID_STATE_OFFSET);
}
/** @hide */
public static int extractFlagsFromKey(@DataBucketKey long key) {
return (int) (key & FLAGS_MASK);
}
/** @hide */
public static String flagsToString(@OpFlags int flags) {
final StringBuilder flagsBuilder = new StringBuilder();
while (flags != 0) {
final int flag = 1 << Integer.numberOfTrailingZeros(flags);
flags &= ~flag;
if (flagsBuilder.length() > 0) {
flagsBuilder.append('|');
}
flagsBuilder.append(getFlagName(flag));
}
return flagsBuilder.toString();
}
// when adding one of these:
// - increment _NUM_OP
// - define an OPSTR_* constant (marked as @SystemApi)
// - 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. */
@UnsupportedAppUsage
public static final int OP_NONE = -1;
/** @hide Access to coarse location information. */
@UnsupportedAppUsage
@TestApi
public static final int OP_COARSE_LOCATION = 0;
/** @hide Access to fine location information. */
@UnsupportedAppUsage
public static final int OP_FINE_LOCATION = 1;
/** @hide Causing GPS to run. */
@UnsupportedAppUsage
public static final int OP_GPS = 2;
/** @hide */
@UnsupportedAppUsage
public static final int OP_VIBRATE = 3;
/** @hide */
@UnsupportedAppUsage
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;
/** @hide */
@UnsupportedAppUsage
public static final int OP_WIFI_SCAN = 10;
/** @hide */
@UnsupportedAppUsage
public static final int OP_POST_NOTIFICATION = 11;
/** @hide */
@UnsupportedAppUsage
public static final int OP_NEIGHBORING_CELLS = 12;
/** @hide */
@UnsupportedAppUsage
public static final int OP_CALL_PHONE = 13;
/** @hide */
@UnsupportedAppUsage
public static final int OP_READ_SMS = 14;
/** @hide */
@UnsupportedAppUsage
public static final int OP_WRITE_SMS = 15;
/** @hide */
@UnsupportedAppUsage
public static final int OP_RECEIVE_SMS = 16;
/** @hide */
@UnsupportedAppUsage
public static final int OP_RECEIVE_EMERGECY_SMS = 17;
/** @hide */
@UnsupportedAppUsage
public static final int OP_RECEIVE_MMS = 18;
/** @hide */
@UnsupportedAppUsage
public static final int OP_RECEIVE_WAP_PUSH = 19;
/** @hide */
@UnsupportedAppUsage
public static final int OP_SEND_SMS = 20;
/** @hide */
@UnsupportedAppUsage
public static final int OP_READ_ICC_SMS = 21;
/** @hide */
@UnsupportedAppUsage
public static final int OP_WRITE_ICC_SMS = 22;
/** @hide */
@UnsupportedAppUsage
public static final int OP_WRITE_SETTINGS = 23;
/** @hide Required to draw on top of other apps. */
@UnsupportedAppUsage
@TestApi
public static final int OP_SYSTEM_ALERT_WINDOW = 24;
/** @hide */
@UnsupportedAppUsage
public static final int OP_ACCESS_NOTIFICATIONS = 25;
/** @hide */
@UnsupportedAppUsage
public static final int OP_CAMERA = 26;
/** @hide */
@UnsupportedAppUsage
@TestApi
public static final int OP_RECORD_AUDIO = 27;
/** @hide */
@UnsupportedAppUsage
public static final int OP_PLAY_AUDIO = 28;
/** @hide */
@UnsupportedAppUsage
public static final int OP_READ_CLIPBOARD = 29;
/** @hide */
@UnsupportedAppUsage
public static final int OP_WRITE_CLIPBOARD = 30;
/** @hide */
@UnsupportedAppUsage
public static final int OP_TAKE_MEDIA_BUTTONS = 31;
/** @hide */
@UnsupportedAppUsage
public static final int OP_TAKE_AUDIO_FOCUS = 32;
/** @hide */
@UnsupportedAppUsage
public static final int OP_AUDIO_MASTER_VOLUME = 33;
/** @hide */
@UnsupportedAppUsage
public static final int OP_AUDIO_VOICE_VOLUME = 34;
/** @hide */
@UnsupportedAppUsage
public static final int OP_AUDIO_RING_VOLUME = 35;
/** @hide */
@UnsupportedAppUsage
public static final int OP_AUDIO_MEDIA_VOLUME = 36;
/** @hide */
@UnsupportedAppUsage
public static final int OP_AUDIO_ALARM_VOLUME = 37;
/** @hide */
@UnsupportedAppUsage
public static final int OP_AUDIO_NOTIFICATION_VOLUME = 38;
/** @hide */
@UnsupportedAppUsage
public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39;
/** @hide */
@UnsupportedAppUsage
public static final int OP_WAKE_LOCK = 40;
/** @hide Continually monitoring location data. */
@UnsupportedAppUsage
public static final int OP_MONITOR_LOCATION = 41;
/** @hide Continually monitoring location data with a relatively high power request. */
@UnsupportedAppUsage
public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
/** @hide Retrieve current usage stats via {@link UsageStatsManager}. */
@UnsupportedAppUsage
public static final int OP_GET_USAGE_STATS = 43;
/** @hide */
@UnsupportedAppUsage
public static final int OP_MUTE_MICROPHONE = 44;
/** @hide */
@UnsupportedAppUsage
public static final int OP_TOAST_WINDOW = 45;
/** @hide Capture the device's display contents and/or audio */
@UnsupportedAppUsage
public static final int OP_PROJECT_MEDIA = 46;
/**
* Start (without additional user intervention) a VPN connection, as used by {@link
* android.net.VpnService} along with as Platform VPN connections, as used by {@link
* android.net.VpnManager}
*
* <p>This appop is granted to apps that have already been given user consent to start
* VpnService based VPN connections. As this is a superset of OP_ACTIVATE_PLATFORM_VPN, this
* appop also allows the starting of Platform VPNs.
*
* @hide
*/
@UnsupportedAppUsage
public static final int OP_ACTIVATE_VPN = 47;
/** @hide Access the WallpaperManagerAPI to write wallpapers. */
@UnsupportedAppUsage
public static final int OP_WRITE_WALLPAPER = 48;
/** @hide Received the assist structure from an app. */
@UnsupportedAppUsage
public static final int OP_ASSIST_STRUCTURE = 49;
/** @hide Received a screenshot from assist. */
@UnsupportedAppUsage
public static final int OP_ASSIST_SCREENSHOT = 50;
/** @hide Read the phone state. */
@UnsupportedAppUsage
public static final int OP_READ_PHONE_STATE = 51;
/** @hide Add voicemail messages to the voicemail content provider. */
@UnsupportedAppUsage
public static final int OP_ADD_VOICEMAIL = 52;
/** @hide Access APIs for SIP calling over VOIP or WiFi. */
@UnsupportedAppUsage
public static final int OP_USE_SIP = 53;
/** @hide Intercept outgoing calls. */
@UnsupportedAppUsage
public static final int OP_PROCESS_OUTGOING_CALLS = 54;
/** @hide User the fingerprint API. */
@UnsupportedAppUsage
public static final int OP_USE_FINGERPRINT = 55;
/** @hide Access to body sensors such as heart rate, etc. */
@UnsupportedAppUsage
public static final int OP_BODY_SENSORS = 56;
/** @hide Read previously received cell broadcast messages. */
@UnsupportedAppUsage
public static final int OP_READ_CELL_BROADCASTS = 57;
/** @hide Inject mock location into the system. */
@UnsupportedAppUsage
public static final int OP_MOCK_LOCATION = 58;
/** @hide Read external storage. */
@UnsupportedAppUsage
public static final int OP_READ_EXTERNAL_STORAGE = 59;
/** @hide Write external storage. */
@UnsupportedAppUsage
public static final int OP_WRITE_EXTERNAL_STORAGE = 60;
/** @hide Turned on the screen. */
@UnsupportedAppUsage
public static final int OP_TURN_SCREEN_ON = 61;
/** @hide Get device accounts. */
@UnsupportedAppUsage
public static final int OP_GET_ACCOUNTS = 62;
/** @hide Control whether an application is allowed to run in the background. */
@UnsupportedAppUsage
public static final int OP_RUN_IN_BACKGROUND = 63;
/** @hide */
@UnsupportedAppUsage
public static final int OP_AUDIO_ACCESSIBILITY_VOLUME = 64;
/** @hide Read the phone number. */
@UnsupportedAppUsage
public static final int OP_READ_PHONE_NUMBERS = 65;
/** @hide Request package installs through package installer */
@UnsupportedAppUsage
public static final int OP_REQUEST_INSTALL_PACKAGES = 66;
/** @hide Enter picture-in-picture. */
@UnsupportedAppUsage
public static final int OP_PICTURE_IN_PICTURE = 67;
/** @hide Instant app start foreground service. */
@UnsupportedAppUsage
public static final int OP_INSTANT_APP_START_FOREGROUND = 68;
/** @hide Answer incoming phone calls */
@UnsupportedAppUsage
public static final int OP_ANSWER_PHONE_CALLS = 69;
/** @hide Run jobs when in background */
@UnsupportedAppUsage
public static final int OP_RUN_ANY_IN_BACKGROUND = 70;
/** @hide Change Wi-Fi connectivity state */
@UnsupportedAppUsage
public static final int OP_CHANGE_WIFI_STATE = 71;
/** @hide Request package deletion through package installer */
@UnsupportedAppUsage
public static final int OP_REQUEST_DELETE_PACKAGES = 72;
/** @hide Bind an accessibility service. */
@UnsupportedAppUsage
public static final int OP_BIND_ACCESSIBILITY_SERVICE = 73;
/** @hide Continue handover of a call from another app */
@UnsupportedAppUsage
public static final int OP_ACCEPT_HANDOVER = 74;
/** @hide Create and Manage IPsec Tunnels */
@UnsupportedAppUsage
public static final int OP_MANAGE_IPSEC_TUNNELS = 75;
/** @hide Any app start foreground service. */
@UnsupportedAppUsage
@TestApi
public static final int OP_START_FOREGROUND = 76;
/** @hide */
@UnsupportedAppUsage
public static final int OP_BLUETOOTH_SCAN = 77;
/** @hide Use the BiometricPrompt/BiometricManager APIs. */
public static final int OP_USE_BIOMETRIC = 78;
/** @hide Physical activity recognition. */
public static final int OP_ACTIVITY_RECOGNITION = 79;
/** @hide Financial app sms read. */
public static final int OP_SMS_FINANCIAL_TRANSACTIONS = 80;
/** @hide Read media of audio type. */
public static final int OP_READ_MEDIA_AUDIO = 81;
/** @hide Write media of audio type. */
public static final int OP_WRITE_MEDIA_AUDIO = 82;
/** @hide Read media of video type. */
public static final int OP_READ_MEDIA_VIDEO = 83;
/** @hide Write media of video type. */
public static final int OP_WRITE_MEDIA_VIDEO = 84;
/** @hide Read media of image type. */
public static final int OP_READ_MEDIA_IMAGES = 85;
/** @hide Write media of image type. */
public static final int OP_WRITE_MEDIA_IMAGES = 86;
/** @hide Has a legacy (non-isolated) view of storage. */
public static final int OP_LEGACY_STORAGE = 87;
/** @hide Accessing accessibility features */
public static final int OP_ACCESS_ACCESSIBILITY = 88;
/** @hide Read the device identifiers (IMEI / MEID, IMSI, SIM / Build serial) */
public static final int OP_READ_DEVICE_IDENTIFIERS = 89;
/** @hide Read location metadata from media */
public static final int OP_ACCESS_MEDIA_LOCATION = 90;
/** @hide Query all apps on device, regardless of declarations in the calling app manifest */
public static final int OP_QUERY_ALL_PACKAGES = 91;
/** @hide Access all external storage */
public static final int OP_MANAGE_EXTERNAL_STORAGE = 92;
/** @hide Communicate cross-profile within the same profile group. */
public static final int OP_INTERACT_ACROSS_PROFILES = 93;
/**
* Start (without additional user intervention) a Platform VPN connection, as used by {@link
* android.net.VpnManager}
*
* <p>This appop is granted to apps that have already been given user consent to start Platform
* VPN connections. This appop is insufficient to start VpnService based VPNs; OP_ACTIVATE_VPN
* is needed for that.
*
* @hide
*/
public static final int OP_ACTIVATE_PLATFORM_VPN = 94;
/** @hide */
@UnsupportedAppUsage
public static final int _NUM_OP = 95;
/** 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 @TestApi
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";
/** Access APIs for diverting outgoing calls */
public static final String OPSTR_PROCESS_OUTGOING_CALLS
= "android:process_outgoing_calls";
/** 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. */
@SystemApi @TestApi
public static final String OPSTR_GET_ACCOUNTS
= "android:get_accounts";
public static final String OPSTR_READ_PHONE_NUMBERS
= "android:read_phone_numbers";
/** Access to picture-in-picture. */
public static final String OPSTR_PICTURE_IN_PICTURE
= "android:picture_in_picture";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_INSTANT_APP_START_FOREGROUND
= "android:instant_app_start_foreground";
/** Answer incoming phone calls */
public static final String OPSTR_ANSWER_PHONE_CALLS
= "android:answer_phone_calls";
/**
* Accept call handover
* @hide
*/
@SystemApi @TestApi
public static final String OPSTR_ACCEPT_HANDOVER
= "android:accept_handover";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_GPS = "android:gps";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_VIBRATE = "android:vibrate";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_WIFI_SCAN = "android:wifi_scan";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_POST_NOTIFICATION = "android:post_notification";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_WRITE_SMS = "android:write_sms";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_RECEIVE_EMERGENCY_BROADCAST =
"android:receive_emergency_broadcast";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_READ_ICC_SMS = "android:read_icc_sms";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_PLAY_AUDIO = "android:play_audio";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_READ_CLIPBOARD = "android:read_clipboard";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_WRITE_CLIPBOARD = "android:write_clipboard";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_TAKE_MEDIA_BUTTONS = "android:take_media_buttons";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_TAKE_AUDIO_FOCUS = "android:take_audio_focus";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_AUDIO_MASTER_VOLUME = "android:audio_master_volume";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_AUDIO_VOICE_VOLUME = "android:audio_voice_volume";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_AUDIO_RING_VOLUME = "android:audio_ring_volume";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_AUDIO_MEDIA_VOLUME = "android:audio_media_volume";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_AUDIO_ALARM_VOLUME = "android:audio_alarm_volume";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_AUDIO_NOTIFICATION_VOLUME =
"android:audio_notification_volume";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_AUDIO_BLUETOOTH_VOLUME = "android:audio_bluetooth_volume";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_WAKE_LOCK = "android:wake_lock";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_TOAST_WINDOW = "android:toast_window";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_PROJECT_MEDIA = "android:project_media";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_ASSIST_STRUCTURE = "android:assist_structure";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_TURN_SCREEN_ON = "android:turn_screen_on";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_RUN_IN_BACKGROUND = "android:run_in_background";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_AUDIO_ACCESSIBILITY_VOLUME =
"android:audio_accessibility_volume";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE =
"android:bind_accessibility_service";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
/** @hide */
@SystemApi @TestApi
public static final String OPSTR_START_FOREGROUND = "android:start_foreground";
/** @hide */
public static final String OPSTR_BLUETOOTH_SCAN = "android:bluetooth_scan";
/** @hide Use the BiometricPrompt/BiometricManager APIs. */
public static final String OPSTR_USE_BIOMETRIC = "android:use_biometric";
/** @hide Recognize physical activity. */
public static final String OPSTR_ACTIVITY_RECOGNITION = "android:activity_recognition";
/** @hide Financial app read sms. */
public static final String OPSTR_SMS_FINANCIAL_TRANSACTIONS =
"android:sms_financial_transactions";
/** @hide Read media of audio type. */
@SystemApi @TestApi
public static final String OPSTR_READ_MEDIA_AUDIO = "android:read_media_audio";
/** @hide Write media of audio type. */
@SystemApi @TestApi
public static final String OPSTR_WRITE_MEDIA_AUDIO = "android:write_media_audio";
/** @hide Read media of video type. */
@SystemApi @TestApi
public static final String OPSTR_READ_MEDIA_VIDEO = "android:read_media_video";
/** @hide Write media of video type. */
@SystemApi @TestApi
public static final String OPSTR_WRITE_MEDIA_VIDEO = "android:write_media_video";
/** @hide Read media of image type. */
@SystemApi @TestApi
public static final String OPSTR_READ_MEDIA_IMAGES = "android:read_media_images";
/** @hide Write media of image type. */
@SystemApi @TestApi
public static final String OPSTR_WRITE_MEDIA_IMAGES = "android:write_media_images";
/** @hide Has a legacy (non-isolated) view of storage. */
@SystemApi @TestApi
public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
/** @hide Read location metadata from media */
public static final String OPSTR_ACCESS_MEDIA_LOCATION = "android:access_media_location";
/** @hide Interact with accessibility. */
@SystemApi
public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
/** @hide Read device identifiers */
public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers";
/** @hide Query all packages on device */
public static final String OPSTR_QUERY_ALL_PACKAGES = "android:query_all_packages";
/** @hide Access all external storage */
@SystemApi
public static final String OPSTR_MANAGE_EXTERNAL_STORAGE =
"android:manage_external_storage";
/** @hide Communicate cross-profile within the same profile group. */
@SystemApi
public static final String OPSTR_INTERACT_ACROSS_PROFILES = "android:interact_across_profiles";
/** @hide Start Platform VPN without user intervention */
public static final String OPSTR_ACTIVATE_PLATFORM_VPN = "android:activate_platform_vpn";
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
private static final byte SHOULD_NOT_COLLECT_NOTE_OP = 1;
/** Should collect noting of this app-op in {@link #sAppOpsToNote} */
private static final byte SHOULD_COLLECT_NOTE_OP = 2;
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "SHOULD_" }, value = {
SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED,
SHOULD_NOT_COLLECT_NOTE_OP,
SHOULD_COLLECT_NOTE_OP
})
private @interface ShouldCollectNoteOp {}
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,
OP_MANAGE_IPSEC_TUNNELS,
OP_INSTANT_APP_START_FOREGROUND,
OP_MANAGE_EXTERNAL_STORAGE,
OP_INTERACT_ACROSS_PROFILES
};
/**
* 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, // 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
OP_QUERY_ALL_PACKAGES, // QUERY_ALL_PACKAGES
OP_MANAGE_EXTERNAL_STORAGE, // MANAGE_EXTERNAL_STORAGE
OP_INTERACT_ACROSS_PROFILES, //INTERACT_ACROSS_PROFILES
OP_ACTIVATE_PLATFORM_VPN, // ACTIVATE_PLATFORM_VPN
};
/**
* This maps each operation to the public string constant for it.
*/
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,
OPSTR_QUERY_ALL_PACKAGES,
OPSTR_MANAGE_EXTERNAL_STORAGE,
OPSTR_INTERACT_ACROSS_PROFILES,
OPSTR_ACTIVATE_PLATFORM_VPN,
};
/**
* 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",
"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",
"AUDIO_ACCESSIBILITY_VOLUME",
"READ_PHONE_NUMBERS",
"REQUEST_INSTALL_PACKAGES",
"PICTURE_IN_PICTURE",
"INSTANT_APP_START_FOREGROUND",
"ANSWER_PHONE_CALLS",
"RUN_ANY_IN_BACKGROUND",
"CHANGE_WIFI_STATE",
"REQUEST_DELETE_PACKAGES",
"BIND_ACCESSIBILITY_SERVICE",
"ACCEPT_HANDOVER",
"MANAGE_IPSEC_TUNNELS",
"START_FOREGROUND",
"BLUETOOTH_SCAN",
"USE_BIOMETRIC",
"ACTIVITY_RECOGNITION",
"SMS_FINANCIAL_TRANSACTIONS",
"READ_MEDIA_AUDIO",
"WRITE_MEDIA_AUDIO",
"READ_MEDIA_VIDEO",
"WRITE_MEDIA_VIDEO",
"READ_MEDIA_IMAGES",
"WRITE_MEDIA_IMAGES",
"LEGACY_STORAGE",
"ACCESS_ACCESSIBILITY",
"READ_DEVICE_IDENTIFIERS",
"ACCESS_MEDIA_LOCATION",
"QUERY_ALL_PACKAGES",
"MANAGE_EXTERNAL_STORAGE",
"INTERACT_ACROSS_PROFILES",
"ACTIVATE_PLATFORM_VPN",
};
/**
* 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
};
/**
* 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
UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_ACCESSIBILITY_VOLUME
null, // READ_PHONE_NUMBERS
null, // REQUEST_INSTALL_PACKAGES
null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
null, // INSTANT_APP_START_FOREGROUND
null, // ANSWER_PHONE_CALLS
null, // OP_RUN_ANY_IN_BACKGROUND
null, // OP_CHANGE_WIFI_STATE
null, // REQUEST_DELETE_PACKAGES
null, // OP_BIND_ACCESSIBILITY_SERVICE
null, // ACCEPT_HANDOVER
null, // MANAGE_IPSEC_TUNNELS
null, // START_FOREGROUND
null, // maybe should be UserManager.DISALLOW_SHARE_LOCATION, //BLUETOOTH_SCAN
null, // USE_BIOMETRIC
null, // ACTIVITY_RECOGNITION
UserManager.DISALLOW_SMS, // SMS_FINANCIAL_TRANSACTIONS
null, // READ_MEDIA_AUDIO
null, // WRITE_MEDIA_AUDIO
null, // READ_MEDIA_VIDEO
null, // WRITE_MEDIA_VIDEO
null, // READ_MEDIA_IMAGES
null, // WRITE_MEDIA_IMAGES
null, // LEGACY_STORAGE
null, // ACCESS_ACCESSIBILITY
null, // READ_DEVICE_IDENTIFIERS
null, // ACCESS_MEDIA_LOCATION
null, // QUERY_ALL_PACKAGES
null, // MANAGE_EXTERNAL_STORAGE
null, // INTERACT_ACROSS_PROFILES
null, // ACTIVATE_PLATFORM_VPN
};
/**
* 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
false, // AUDIO_ACCESSIBILITY_VOLUME
false, // READ_PHONE_NUMBERS
false, // REQUEST_INSTALL_PACKAGES
false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
false, // INSTANT_APP_START_FOREGROUND
false, // ANSWER_PHONE_CALLS
false, // OP_RUN_ANY_IN_BACKGROUND
false, // OP_CHANGE_WIFI_STATE
false, // OP_REQUEST_DELETE_PACKAGES
false, // OP_BIND_ACCESSIBILITY_SERVICE
false, // ACCEPT_HANDOVER
false, // MANAGE_IPSEC_HANDOVERS
false, // START_FOREGROUND
true, // BLUETOOTH_SCAN
false, // USE_BIOMETRIC
false, // ACTIVITY_RECOGNITION
false, // SMS_FINANCIAL_TRANSACTIONS
false, // READ_MEDIA_AUDIO
false, // WRITE_MEDIA_AUDIO
false, // READ_MEDIA_VIDEO
false, // WRITE_MEDIA_VIDEO
false, // READ_MEDIA_IMAGES
false, // WRITE_MEDIA_IMAGES
false, // LEGACY_STORAGE
false, // ACCESS_ACCESSIBILITY
false, // READ_DEVICE_IDENTIFIERS
false, // ACCESS_MEDIA_LOCATION
false, // QUERY_ALL_PACKAGES
false, // MANAGE_EXTERNAL_STORAGE
false, // INTERACT_ACROSS_PROFILES
false, // ACTIVATE_PLATFORM_VPN
};
/**
* 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
AppOpsManager.MODE_DEFAULT, // QUERY_ALL_PACKAGES
AppOpsManager.MODE_DEFAULT, // MANAGE_EXTERNAL_STORAGE
AppOpsManager.MODE_DEFAULT, // INTERACT_ACROSS_PROFILES
AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN
};
/**
* 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, // COARSE_LOCATION
false, // 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
false, // WIFI_SCAN
false, // POST_NOTIFICATION
false, // NEIGHBORING_CELLS
false, // CALL_PHONE
true, // READ_SMS
true, // WRITE_SMS
true, // RECEIVE_SMS
false, // RECEIVE_EMERGENCY_BROADCAST
false, // RECEIVE_MMS
true, // RECEIVE_WAP_PUSH
true, // SEND_SMS
false, // READ_ICC_SMS
false, // WRITE_ICC_SMS
false, // WRITE_SETTINGS
false, // 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
false, // TOAST_WINDOW
false, // PROJECT_MEDIA
false, // ACTIVATE_VPN
false, // WRITE_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
true, // READ_CELL_BROADCASTS
false, // MOCK_LOCATION
false, // READ_EXTERNAL_STORAGE
false, // WRITE_EXTERNAL_STORAGE
false, // TURN_SCREEN_ON
false, // GET_ACCOUNTS
false, // RUN_IN_BACKGROUND
false, // AUDIO_ACCESSIBILITY_VOLUME
false, // READ_PHONE_NUMBERS
false, // REQUEST_INSTALL_PACKAGES
false, // PICTURE_IN_PICTURE
false, // INSTANT_APP_START_FOREGROUND
false, // ANSWER_PHONE_CALLS
false, // RUN_ANY_IN_BACKGROUND
false, // CHANGE_WIFI_STATE
false, // REQUEST_DELETE_PACKAGES
false, // BIND_ACCESSIBILITY_SERVICE
false, // ACCEPT_HANDOVER
false, // MANAGE_IPSEC_TUNNELS
false, // START_FOREGROUND
false, // BLUETOOTH_SCAN
false, // USE_BIOMETRIC
false, // ACTIVITY_RECOGNITION
false, // SMS_FINANCIAL_TRANSACTIONS
false, // READ_MEDIA_AUDIO
false, // WRITE_MEDIA_AUDIO
false, // READ_MEDIA_VIDEO
false, // WRITE_MEDIA_VIDEO
false, // READ_MEDIA_IMAGES
false, // WRITE_MEDIA_IMAGES
true, // LEGACY_STORAGE
false, // ACCESS_ACCESSIBILITY
false, // READ_DEVICE_IDENTIFIERS
false, // ACCESS_MEDIA_LOCATION
false, // QUERY_ALL_PACKAGES
false, // MANAGE_EXTERNAL_STORAGE
false, // INTERACT_ACROSS_PROFILES
false, // ACTIVATE_PLATFORM_VPN
};
/**
* Mapping from an app op name to the app op code.
*/
private static HashMap<String, Integer> sOpStrToOp = new HashMap<>();
/**
* Mapping from a permission to the corresponding app op.
*/
private static HashMap<String, Integer> sPermToOp = new HashMap<>();
/**
* Set to the uid of the caller if this thread is currently executing a two-way binder
* transaction. Not set if this thread is currently not executing a two way binder transaction.
*
* @see #startNotedAppOpsCollection
* @see #getNotedOpCollectionMode
*/
private static final ThreadLocal<Integer> sBinderThreadCallingUid = new ThreadLocal<>();
/**
* If a thread is currently executing a two-way binder transaction, this stores the op-codes of
* the app-ops that were noted during this transaction.
*
* @see #getNotedOpCollectionMode
* @see #collectNotedOpSync
*/
private static final ThreadLocal<ArrayMap<String, long[]>> sAppOpsNotedInThisBinderTransaction =
new ThreadLocal<>();
/** Whether noting for an appop should be collected */
private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP];
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_AND_APPOP_PERMISSIONS_OPS) {
if (sOpPerms[op] != null) {
sPermToOp.put(sOpPerms[op], op);
}
}
if ((_NUM_OP + Long.SIZE - 1) / Long.SIZE != 2) {
// The code currently assumes that the length of sAppOpsNotedInThisBinderTransaction is
// two longs
throw new IllegalStateException("notedAppOps collection code assumes < 128 appops");
}
}
/** @hide */
public static final String KEY_HISTORICAL_OPS = "historical_ops";
/** System properties for debug logging of noteOp call sites */
private static final String DEBUG_LOGGING_ENABLE_PROP = "appops.logging_enabled";
private static final String DEBUG_LOGGING_PACKAGES_PROP = "appops.logging_packages";
private static final String DEBUG_LOGGING_OPS_PROP = "appops.logging_ops";
private static final String DEBUG_LOGGING_TAG = "AppOpsManager";
/**
* Retrieve the op switch that controls the given operation.
* @hide
*/
@UnsupportedAppUsage
public static int opToSwitch(int op) {
return sOpToSwitch[op];
}
/**
* Retrieve a non-localized name for the operation, for debugging output.
* @hide
*/
@UnsupportedAppUsage
public static String opToName(int op) {
if (op == OP_NONE) return "NONE";
return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")");
}
/**
* Retrieve a non-localized public name for the operation.
*
* @hide
*/
public static @NonNull String opToPublicName(int op) {
return sOpToString[op];
}
/**
* @hide
*/
public static int strDebugOpToOp(String op) {
for (int i=0; i<sOpNames.length; i++) {
if (sOpNames[i].equals(op)) {
return i;
}
}
throw new IllegalArgumentException("Unknown operation string: " + op);
}
/**
* Retrieve the permission associated with an operation, or null if there is not one.
* @hide
*/
@UnsupportedAppUsage
@TestApi
public static String opToPermission(int op) {
return sOpPerms[op];
}
/**
* Retrieve the permission associated with an operation, or null if there is not one.
*
* @param op The operation name.
*
* @hide
*/
@Nullable
@SystemApi
public static String opToPermission(@NonNull String op) {
return opToPermission(strOpToOp(op));
}
/**
* Retrieve the user restriction associated with an operation, or null if there is not one.
* @hide
*/
public static String opToRestriction(int op) {
return sOpRestrictions[op];
}
/**
* Retrieve the app op code for a permission, or null if there is not one.
* This API is intended to be used for mapping runtime or appop permissions
* to the corresponding app op.
* @hide
*/
@UnsupportedAppUsage
@TestApi
public static int permissionToOpCode(String permission) {
Integer boxedOpCode = sPermToOp.get(permission);
return boxedOpCode != null ? boxedOpCode : OP_NONE;
}
/**
* Retrieve whether the op allows the system (and system ui) to
* bypass the user restriction.
* @hide
*/
public static boolean opAllowSystemBypassRestriction(int op) {
return sOpAllowSystemRestrictionBypass[op];
}
/**
* Retrieve the default mode for the operation.
* @hide
*/
public static @Mode int opToDefaultMode(int op) {
return sOpDefaultMode[op];
}
/**
* Retrieve the default mode for the app op.
*
* @param appOp The app op name
*
* @return the default mode for the app op
*
* @hide
*/
@TestApi
@SystemApi
public static int opToDefaultMode(@NonNull String appOp) {
return opToDefaultMode(strOpToOp(appOp));
}
/**
* Retrieve the human readable mode.
* @hide
*/
public static String modeToName(@Mode int mode) {
if (mode >= 0 && mode < MODE_NAMES.length) {
return MODE_NAMES[mode];
}
return "mode=" + mode;
}
/**
* Retrieve whether the op allows itself to be reset.
* @hide
*/
public static boolean opAllowsReset(int op) {
return !sOpDisableReset[op];
}
/**
* Class holding all of the operation information associated with an app.
* @hide
*/
@TestApi
@SystemApi
public static final class PackageOps implements Parcelable {
private final String mPackageName;
private final int mUid;
private final List<OpEntry> mEntries;
/**
* @hide
*/
@UnsupportedAppUsage
public PackageOps(String packageName, int uid, List<OpEntry> entries) {
mPackageName = packageName;
mUid = uid;
mEntries = entries;
}
/**
* @return The name of the package.
*/
public @NonNull String getPackageName() {
return mPackageName;
}
/**
* @return The uid of the package.
*/
public int getUid() {
return mUid;
}
/**
* @return The ops of the package.
*/
public @NonNull List<OpEntry> getOps() {
return mEntries;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mPackageName);
dest.writeInt(mUid);
dest.writeInt(mEntries.size());
for (int i=0; i<mEntries.size(); i++) {
mEntries.get(i).writeToParcel(dest, flags);
}
}
PackageOps(Parcel source) {
mPackageName = source.readString();
mUid = source.readInt();
mEntries = new ArrayList<OpEntry>();
final int N = source.readInt();
for (int i=0; i<N; i++) {
mEntries.add(OpEntry.CREATOR.createFromParcel(source));
}
}
public static final @android.annotation.NonNull Creator<PackageOps> CREATOR = new Creator<PackageOps>() {
@Override public PackageOps createFromParcel(Parcel source) {
return new PackageOps(source);
}
@Override public PackageOps[] newArray(int size) {
return new PackageOps[size];
}
};
}
/**
* Proxy information for a {@link #noteOp} event
*
* @hide
*/
@TestApi
@SystemApi
// @DataClass(genHiddenConstructor = true, genHiddenCopyConstructor = true)
// genHiddenCopyConstructor does not work for @hide @SystemApi classes
public static final class OpEventProxyInfo implements Parcelable {
/** UID of the proxy app that noted the op */
private @IntRange(from = 0) int mUid;
/** Package of the proxy that noted the op */
private @Nullable String mPackageName;
/** ID of the feature of the proxy that noted the op */
private @Nullable String mFeatureId;
/**
* Reinit existing object with new state.
*
* @param uid UID of the proxy app that noted the op
* @param packageName Package of the proxy that noted the op
* @param featureId ID of the feature of the proxy that noted the op
*
* @hide
*/
public void reinit(@IntRange(from = 0) int uid, @Nullable String packageName,
@Nullable String featureId) {
mUid = Preconditions.checkArgumentNonnegative(uid);
mPackageName = packageName;
mFeatureId = featureId;
}
// Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/AppOpsManager.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
/**
* Creates a new OpEventProxyInfo.
*
* @param uid
* UID of the proxy app that noted the op
* @param packageName
* Package of the proxy that noted the op
* @param featureId
* ID of the feature of the proxy that noted the op
* @hide
*/
@DataClass.Generated.Member
public OpEventProxyInfo(
@IntRange(from = 0) int uid,
@Nullable String packageName,
@Nullable String featureId) {
this.mUid = uid;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mUid,
"from", 0);
this.mPackageName = packageName;
this.mFeatureId = featureId;
// onConstructed(); // You can define this method to get a callback
}
/**
* Copy constructor
*
* @hide
*/
@DataClass.Generated.Member
public OpEventProxyInfo(@NonNull OpEventProxyInfo orig) {
mUid = orig.mUid;
mPackageName = orig.mPackageName;
mFeatureId = orig.mFeatureId;
}
/**
* UID of the proxy app that noted the op
*/
@DataClass.Generated.Member
public @IntRange(from = 0) int getUid() {
return mUid;
}
/**
* Package of the proxy that noted the op
*/
@DataClass.Generated.Member
public @Nullable String getPackageName() {
return mPackageName;
}
/**
* ID of the feature of the proxy that noted the op
*/
@DataClass.Generated.Member
public @Nullable String getFeatureId() {
return mFeatureId;
}
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
if (mPackageName != null) flg |= 0x2;
if (mFeatureId != null) flg |= 0x4;
dest.writeByte(flg);
dest.writeInt(mUid);
if (mPackageName != null) dest.writeString(mPackageName);
if (mFeatureId != null) dest.writeString(mFeatureId);
}
@Override
@DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
/* package-private */ OpEventProxyInfo(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
int uid = in.readInt();
String packageName = (flg & 0x2) == 0 ? null : in.readString();
String featureId = (flg & 0x4) == 0 ? null : in.readString();
this.mUid = uid;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mUid,
"from", 0);
this.mPackageName = packageName;
this.mFeatureId = featureId;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<OpEventProxyInfo> CREATOR
= new Parcelable.Creator<OpEventProxyInfo>() {
@Override
public OpEventProxyInfo[] newArray(int size) {
return new OpEventProxyInfo[size];
}
@Override
public OpEventProxyInfo createFromParcel(@NonNull Parcel in) {
return new OpEventProxyInfo(in);
}
};
/*
@DataClass.Generated(
time = 1576814974615L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
inputSignatures = "private @android.annotation.IntRange(from=0L) int mUid\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.Nullable java.lang.String mFeatureId\npublic void reinit(int,java.lang.String,java.lang.String)\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genHiddenCopyConstructor=true)")
@Deprecated
private void __metadata() {}
*/
//@formatter:on
// End of generated code
}
/**
* Description of a {@link #noteOp} or {@link #startOp} event
*
* @hide
*/
//@DataClass codegen verifier is broken
public static final class NoteOpEvent implements Parcelable {
/** Time of noteOp event */
private @IntRange(from = 0) long mNoteTime;
/** The duration of this event (in case this is a startOp event, -1 otherwise). */
private @IntRange(from = -1) long mDuration;
/** Proxy information of the noteOp event */
private @Nullable OpEventProxyInfo mProxy;
/**
* Reinit existing object with new state.
*
* @param noteTime Time of noteOp event
* @param duration The duration of this event (in case this is a startOp event,
* -1 otherwise).
* @param proxy Proxy information of the noteOp event
* @param proxyPool The pool to release previous {@link OpEventProxyInfo} to
*/
public void reinit(@IntRange(from = 0) long noteTime,
@IntRange(from = -1) long duration,
@Nullable OpEventProxyInfo proxy,
@NonNull Pools.Pool<OpEventProxyInfo> proxyPool) {
mNoteTime = Preconditions.checkArgumentNonnegative(noteTime);
mDuration = Preconditions.checkArgumentInRange(duration, -1L, Long.MAX_VALUE,
"duration");
if (mProxy != null) {
proxyPool.release(mProxy);
}
mProxy = proxy;
}
/**
* Copy constructor
*
* @hide
*/
public NoteOpEvent(@NonNull NoteOpEvent original) {
this(original.mNoteTime, original.mDuration,
original.mProxy != null ? new OpEventProxyInfo(original.mProxy) : null);
}
// Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/AppOpsManager.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
/**
* Creates a new NoteOpEvent.
*
* @param noteTime
* Time of noteOp event
* @param duration
* The duration of this event (in case this is a startOp event, -1 otherwise).
* @param proxy
* Proxy information of the noteOp event
*/
@DataClass.Generated.Member
public NoteOpEvent(
@IntRange(from = 0) long noteTime,
@IntRange(from = -1) long duration,
@Nullable OpEventProxyInfo proxy) {
this.mNoteTime = noteTime;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mNoteTime,
"from", 0);
this.mDuration = duration;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mDuration,
"from", -1);
this.mProxy = proxy;
// onConstructed(); // You can define this method to get a callback
}
/**
* Time of noteOp event
*/
@DataClass.Generated.Member
public @IntRange(from = 0) long getNoteTime() {
return mNoteTime;
}
/**
* The duration of this event (in case this is a startOp event, -1 otherwise).
*/
@DataClass.Generated.Member
public @IntRange(from = -1) long getDuration() {
return mDuration;
}
/**
* Proxy information of the noteOp event
*/
@DataClass.Generated.Member
public @Nullable OpEventProxyInfo getProxy() {
return mProxy;
}
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
if (mProxy != null) flg |= 0x4;
dest.writeByte(flg);
dest.writeLong(mNoteTime);
dest.writeLong(mDuration);
if (mProxy != null) dest.writeTypedObject(mProxy, flags);
}
@Override
@DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
/* package-private */ NoteOpEvent(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
long noteTime = in.readLong();
long duration = in.readLong();
OpEventProxyInfo proxy = (flg & 0x4) == 0 ? null : (OpEventProxyInfo) in.readTypedObject(OpEventProxyInfo.CREATOR);
this.mNoteTime = noteTime;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mNoteTime,
"from", 0);
this.mDuration = duration;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mDuration,
"from", -1);
this.mProxy = proxy;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<NoteOpEvent> CREATOR
= new Parcelable.Creator<NoteOpEvent>() {
@Override
public NoteOpEvent[] newArray(int size) {
return new NoteOpEvent[size];
}
@Override
public NoteOpEvent createFromParcel(@NonNull Parcel in) {
return new NoteOpEvent(in);
}
};
/*
@DataClass.Generated(
time = 1576811792274L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
inputSignatures = "private @android.annotation.IntRange(from=0L) long mNoteTime\nprivate @android.annotation.IntRange(from=-1) long mDuration\nprivate @android.annotation.Nullable android.app.OpEventProxyInfo mProxy\npublic void reinit(long,long,android.app.OpEventProxyInfo,android.util.Pools.Pool<android.app.OpEventProxyInfo>)\npublic @java.lang.Override java.lang.Object clone()\nclass NoteOpEvent extends java.lang.Object implements [android.os.Parcelable, java.lang.Cloneable]\n@com.android.internal.util.DataClass")
@Deprecated
private void __metadata() {}
*/
//@formatter:on
// End of generated code
}
/**
* Last {@link #noteOp} and {@link #startOp} events performed for a single op and a specific
* {@link Context#createFeatureContext(String) feature} for all uidModes and opFlags.
*
* @hide
*/
@TestApi
@SystemApi
@Immutable
// @DataClass(genHiddenConstructor = true) codegen verifier is broken
@DataClass.Suppress({"getAccessEvents", "getRejectEvents", "getOp"})
public static final class OpFeatureEntry implements Parcelable {
/** The code of the op */
private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp;
/** Whether the op is running */
private final boolean mRunning;
/** The access events */
@DataClass.ParcelWith(LongSparseArrayParceling.class)
private final @Nullable LongSparseArray<NoteOpEvent> mAccessEvents;
/** The rejection events */
@DataClass.ParcelWith(LongSparseArrayParceling.class)
private final @Nullable LongSparseArray<NoteOpEvent> mRejectEvents;
/**
* Returns all keys for which we have events.
*
* @hide
*/
public @NonNull ArraySet<Long> collectKeys() {
ArraySet<Long> keys = new ArraySet<>();
if (mAccessEvents != null) {
int numEvents = mAccessEvents.size();
for (int i = 0; i < numEvents; i++) {
keys.add(mAccessEvents.keyAt(i));
}
}
if (mRejectEvents != null) {
int numEvents = mRejectEvents.size();
for (int i = 0; i < numEvents; i++) {
keys.add(mRejectEvents.keyAt(i));
}
}
return keys;
}
/**
* Return the last access time.
*
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastAccessForegroundTime(int)
* @see #getLastAccessBackgroundTime(int)
* @see #getLastAccessTime(int, int, int)
* @see OpEntry#getLastAccessTime(int)
*/
public long getLastAccessTime(@OpFlags int flags) {
return getLastAccessTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
}
/**
* Return the last foreground access time.
*
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastAccessTime(int)
* @see #getLastAccessBackgroundTime(int)
* @see #getLastAccessTime(int, int, int)
* @see OpEntry#getLastAccessForegroundTime(int)
*/
public long getLastAccessForegroundTime(@OpFlags int flags) {
return getLastAccessTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
flags);
}
/**
* Return the last background access time.
*
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastAccessTime(int)
* @see #getLastAccessForegroundTime(int)
* @see #getLastAccessTime(int, int, int)
* @see OpEntry#getLastAccessBackgroundTime(int)
*/
public long getLastAccessBackgroundTime(@OpFlags int flags) {
return getLastAccessTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
flags);
}
/**
* Return the last access event.
*
* @param flags The op flags
*
* @return the last access event of {@code null}
*/
private @Nullable NoteOpEvent getLastAccessEvent(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
return getLastEvent(mAccessEvents, fromUidState, toUidState, flags);
}
/**
* Return the last access time.
*
* @param fromUidState The lowest UID state for which to query
* @param toUidState The highest UID state for which to query (inclusive)
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastAccessTime(int)
* @see #getLastAccessForegroundTime(int)
* @see #getLastAccessBackgroundTime(int)
* @see OpEntry#getLastAccessTime(int, int, int)
*/
public long getLastAccessTime(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);
if (lastEvent == null) {
return -1;
}
return lastEvent.getNoteTime();
}
/**
* Return the last rejection time.
*
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectBackgroundTime(int)
* @see #getLastRejectTime(int, int, int)
* @see OpEntry#getLastRejectTime(int)
*/
public long getLastRejectTime(@OpFlags int flags) {
return getLastRejectTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
}
/**
* Return the last foreground rejection time.
*
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastRejectTime(int)
* @see #getLastRejectBackgroundTime(int)
* @see #getLastRejectTime(int, int, int)
* @see OpEntry#getLastRejectForegroundTime(int)
*/
public long getLastRejectForegroundTime(@OpFlags int flags) {
return getLastRejectTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
flags);
}
/**
* Return the last background rejection time.
*
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastRejectTime(int)
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectTime(int, int, int)
* @see OpEntry#getLastRejectBackgroundTime(int)
*/
public long getLastRejectBackgroundTime(@OpFlags int flags) {
return getLastRejectTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
flags);
}
/**
* Return the last background rejection event.
*
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastRejectTime(int)
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectBackgroundTime(int)
* @see OpEntry#getLastRejectTime(int, int, int)
*/
private @Nullable NoteOpEvent getLastRejectEvent(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
return getLastEvent(mRejectEvents, fromUidState, toUidState, flags);
}
/**
* Return the last rejection time.
*
* @param fromUidState The lowest UID state for which to query
* @param toUidState The highest UID state for which to query (inclusive)
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch) or {@code -1}
*
* @see #getLastRejectTime(int)
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectTime(int, int, int)
* @see OpEntry#getLastRejectTime(int, int, int)
*/
public long getLastRejectTime(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
NoteOpEvent lastEvent = getLastRejectEvent(fromUidState, toUidState, flags);
if (lastEvent == null) {
return -1;
}
return lastEvent.getNoteTime();
}
/**
* Return the duration in milliseconds of the last the access.
*
* @param flags The op flags
*
* @return the duration in milliseconds or {@code -1}
*
* @see #getLastForegroundDuration(int)
* @see #getLastBackgroundDuration(int)
* @see #getLastDuration(int, int, int)
* @see OpEntry#getLastDuration(int)
*/
public long getLastDuration(@OpFlags int flags) {
return getLastDuration(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
}
/**
* Return the duration in milliseconds of the last foreground access.
*
* @param flags The op flags
*
* @return the duration in milliseconds or {@code -1}
*
* @see #getLastDuration(int)
* @see #getLastBackgroundDuration(int)
* @see #getLastDuration(int, int, int)
* @see OpEntry#getLastForegroundDuration(int)
*/
public long getLastForegroundDuration(@OpFlags int flags) {
return getLastDuration(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
flags);
}
/**
* Return the duration in milliseconds of the last background access.
*
* @param flags The op flags
*
* @return the duration in milliseconds or {@code -1}
*
* @see #getLastDuration(int)
* @see #getLastForegroundDuration(int)
* @see #getLastDuration(int, int, int)
* @see OpEntry#getLastBackgroundDuration(int)
*/
public long getLastBackgroundDuration(@OpFlags int flags) {
return getLastDuration(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
flags);
}
/**
* Return the duration in milliseconds of the last access.
*
* @param fromUidState The lowest UID state for which to query
* @param toUidState The highest UID state for which to query (inclusive)
* @param flags The op flags
*
* @return the duration in milliseconds or {@code -1}
*
* @see #getLastDuration(int)
* @see #getLastForegroundDuration(int)
* @see #getLastBackgroundDuration(int)
* @see #getLastDuration(int, int, int)
* @see OpEntry#getLastDuration(int, int, int)
*/
public long getLastDuration(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);;
if (lastEvent == null) {
return -1;
}
return lastEvent.getDuration();
}
/**
* Gets the proxy info of the app that performed the last access on behalf of this feature
* and as a result blamed the op on this app.
*
* @param flags The op flags
*
* @return The proxy name or {@code null}
*
* @see #getLastForegroundProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
* @see #getLastProxyInfo(int, int, int)
* @see OpEntry#getLastProxyInfo(int)
*/
public @Nullable OpEventProxyInfo getLastProxyInfo(@OpFlags int flags) {
return getLastProxyInfo(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
}
/**
* Gets the proxy info of the app that performed the last foreground access on behalf of
* this feature and as a result blamed the op on this app.
*
* @param flags The op flags
*
* @return The proxy name or {@code null}
*
* @see #getLastProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
* @see #getLastProxyInfo(int, int, int)
* @see OpEntry#getLastForegroundProxyInfo(int)
*/
public @Nullable OpEventProxyInfo getLastForegroundProxyInfo(@OpFlags int flags) {
return getLastProxyInfo(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
flags);
}
/**
* Gets the proxy info of the app that performed the last background access on behalf of
* this feature and as a result blamed the op on this app.
*
* @param flags The op flags
*
* @return The proxy name or {@code null}
*
* @see #getLastProxyInfo(int)
* @see #getLastForegroundProxyInfo(int)
* @see #getLastProxyInfo(int, int, int)
* @see OpEntry#getLastBackgroundProxyInfo(int)
*/
public @Nullable OpEventProxyInfo getLastBackgroundProxyInfo(@OpFlags int flags) {
return getLastProxyInfo(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
flags);
}
/**
* Gets the proxy info of the app that performed the last access on behalf of this feature
* and as a result blamed the op on this app.
*
* @param fromUidState The lowest UID state for which to query
* @param toUidState The highest UID state for which to query (inclusive)
* @param flags The op flags
*
* @return The proxy name or {@code null}
*
* @see #getLastProxyInfo(int)
* @see #getLastForegroundProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
* @see OpEntry#getLastProxyInfo(int, int, int)
*/
public @Nullable OpEventProxyInfo getLastProxyInfo(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);
if (lastEvent == null) {
return null;
}
return lastEvent.getProxy();
}
private static class LongSparseArrayParceling implements
Parcelling<LongSparseArray<NoteOpEvent>> {
@Override
public void parcel(@Nullable LongSparseArray<NoteOpEvent> array, @NonNull Parcel dest,
int parcelFlags) {
if (array == null) {
dest.writeInt(-1);
return;
}
int numEntries = array.size();
dest.writeInt(numEntries);
for (int i = 0; i < numEntries; i++) {
dest.writeLong(array.keyAt(i));
dest.writeParcelable(array.valueAt(i), parcelFlags);
}
}
@Override
public @Nullable LongSparseArray<NoteOpEvent> unparcel(@NonNull Parcel source) {
int numEntries = source.readInt();
if (numEntries == -1) {
return null;
}
LongSparseArray<NoteOpEvent> array = new LongSparseArray<>(numEntries);
for (int i = 0; i < numEntries; i++) {
array.put(source.readLong(), source.readParcelable(null));
}
return array;
}
}
// Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/AppOpsManager.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
/**
* Creates a new OpFeatureEntry.
*
* @param op
* The code of the op
* @param running
* Whether the op is running
* @param accessEvents
* The access events
* @param rejectEvents
* The rejection events
* @hide
*/
@DataClass.Generated.Member
public OpFeatureEntry(
@IntRange(from = 0, to = _NUM_OP - 1) int op,
boolean running,
@Nullable LongSparseArray<NoteOpEvent> accessEvents,
@Nullable LongSparseArray<NoteOpEvent> rejectEvents) {
this.mOp = op;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOp,
"from", 0,
"to", _NUM_OP - 1);
this.mRunning = running;
this.mAccessEvents = accessEvents;
this.mRejectEvents = rejectEvents;
// onConstructed(); // You can define this method to get a callback
}
/**
* Whether the op is running
*/
@DataClass.Generated.Member
public boolean isRunning() {
return mRunning;
}
@DataClass.Generated.Member
static Parcelling<LongSparseArray<NoteOpEvent>> sParcellingForAccessEvents =
Parcelling.Cache.get(
LongSparseArrayParceling.class);
static {
if (sParcellingForAccessEvents == null) {
sParcellingForAccessEvents = Parcelling.Cache.put(
new LongSparseArrayParceling());
}
}
@DataClass.Generated.Member
static Parcelling<LongSparseArray<NoteOpEvent>> sParcellingForRejectEvents =
Parcelling.Cache.get(
LongSparseArrayParceling.class);
static {
if (sParcellingForRejectEvents == null) {
sParcellingForRejectEvents = Parcelling.Cache.put(
new LongSparseArrayParceling());
}
}
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
if (mRunning) flg |= 0x2;
if (mAccessEvents != null) flg |= 0x4;
if (mRejectEvents != null) flg |= 0x8;
dest.writeByte(flg);
dest.writeInt(mOp);
sParcellingForAccessEvents.parcel(mAccessEvents, dest, flags);
sParcellingForRejectEvents.parcel(mRejectEvents, dest, flags);
}
@Override
@DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
/* package-private */ OpFeatureEntry(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
boolean running = (flg & 0x2) != 0;
int op = in.readInt();
LongSparseArray<NoteOpEvent> accessEvents = sParcellingForAccessEvents.unparcel(in);
LongSparseArray<NoteOpEvent> rejectEvents = sParcellingForRejectEvents.unparcel(in);
this.mOp = op;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOp,
"from", 0,
"to", _NUM_OP - 1);
this.mRunning = running;
this.mAccessEvents = accessEvents;
this.mRejectEvents = rejectEvents;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<OpFeatureEntry> CREATOR
= new Parcelable.Creator<OpFeatureEntry>() {
@Override
public OpFeatureEntry[] newArray(int size) {
return new OpFeatureEntry[size];
}
@Override
public OpFeatureEntry createFromParcel(@NonNull Parcel in) {
return new OpFeatureEntry(in);
}
};
/*
@DataClass.Generated(
time = 1574809856239L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final boolean mRunning\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpFeatureEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mAccessEvents\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpFeatureEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mRejectEvents\npublic @android.annotation.NonNull android.util.ArraySet<java.lang.Long> collectKeys()\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic long getAccessTime(int,int)\npublic long getRejectTime(int,int)\npublic long getDuration(int,int)\npublic int getProxyUid(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyFeatureId(int,int)\nclass OpFeatureEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
*/
//@formatter:on
// End of generated code
}
/**
* Last {@link #noteOp} and {@link #startOp} events performed for a single op for all uidModes
* and opFlags.
*
* @hide
*/
@TestApi
@Immutable
@SystemApi
// @DataClass(genHiddenConstructor = true) codegen verifier is broken
public static final class OpEntry implements Parcelable {
/** The code of the op */
private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp;
/** The mode of the op */
private final @Mode int mMode;
/** The features that have been used when checking the op */
private final @NonNull Map<String, OpFeatureEntry> mFeatures;
/**
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@code "
+ "#getOpStr()}")
public int getOp() {
return mOp;
}
/**
* @return This entry's op string name, such as {@link #OPSTR_COARSE_LOCATION}.
*/
public @NonNull String getOpStr() {
return sOpToString[mOp];
}
/**
* @hide
*
* @deprecated Use {@link #getLastAccessTime(int)} instead
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@code "
+ "#getLastAccessTime(int)}")
public long getTime() {
return getLastAccessTime(OP_FLAGS_ALL);
}
/**
* Return the last access time.
*
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastAccessForegroundTime(int)
* @see #getLastAccessBackgroundTime(int)
* @see #getLastAccessTime(int, int, int)
* @see OpFeatureEntry#getLastAccessTime(int)
*/
public long getLastAccessTime(@OpFlags int flags) {
return getLastAccessTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
}
/**
* Return the last foreground access time.
*
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastAccessTime(int)
* @see #getLastAccessBackgroundTime(int)
* @see #getLastAccessTime(int, int, int)
* @see OpFeatureEntry#getLastAccessForegroundTime(int)
*/
public long getLastAccessForegroundTime(@OpFlags int flags) {
return getLastAccessTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
flags);
}
/**
* Return the last background access time.
*
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastAccessTime(int)
* @see #getLastAccessForegroundTime(int)
* @see #getLastAccessTime(int, int, int)
* @see OpFeatureEntry#getLastAccessBackgroundTime(int)
*/
public long getLastAccessBackgroundTime(@OpFlags int flags) {
return getLastAccessTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
flags);
}
/**
* Return the last access event.
*
* @param flags The op flags
*
* @return the last access event of {@code null}
*/
private @Nullable NoteOpEvent getLastAccessEvent(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
NoteOpEvent lastAccessEvent = null;
for (OpFeatureEntry featureEntry : mFeatures.values()) {
NoteOpEvent lastFeatureAccessEvent = featureEntry.getLastAccessEvent(fromUidState,
toUidState, flags);
if (lastAccessEvent == null || (lastFeatureAccessEvent != null
&& lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
lastAccessEvent = lastFeatureAccessEvent;
}
}
return lastAccessEvent;
}
/**
* Return the last access time.
*
* @param fromUidState the lowest uid state to query
* @param toUidState the highest uid state to query (inclusive)
* @param flags The op flags
*
* @return the last access time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastAccessTime(int)
* @see #getLastAccessForegroundTime(int)
* @see #getLastAccessBackgroundTime(int)
* @see OpFeatureEntry#getLastAccessTime(int, int, int)
*/
public long getLastAccessTime(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);;
if (lastEvent == null) {
return -1;
}
return lastEvent.getNoteTime();
}
/**
* @hide
*
* @deprecated Use {@link #getLastRejectTime(int)} instead
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "{@code "
+ "#getLastRejectTime(int)}")
public long getRejectTime() {
return getLastRejectTime(OP_FLAGS_ALL);
}
/**
* Return the last rejection time.
*
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectBackgroundTime(int)
* @see #getLastRejectTime(int, int, int)
* @see OpFeatureEntry#getLastRejectTime(int)
*/
public long getLastRejectTime(@OpFlags int flags) {
return getLastRejectTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
}
/**
* Return the last foreground rejection time.
*
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastRejectTime(int)
* @see #getLastRejectBackgroundTime(int)
* @see #getLastRejectTime(int, int, int)
* @see OpFeatureEntry#getLastRejectForegroundTime(int)
*/
public long getLastRejectForegroundTime(@OpFlags int flags) {
return getLastRejectTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
flags);
}
/**
* Return the last background rejection time.
*
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastRejectTime(int)
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectTime(int, int, int)
* @see OpFeatureEntry#getLastRejectBackgroundTime(int)
*/
public long getLastRejectBackgroundTime(@OpFlags int flags) {
return getLastRejectTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
flags);
}
/**
* Return the last rejection event.
*
* @param flags The op flags
*
* @return the last reject event of {@code null}
*/
private @Nullable NoteOpEvent getLastRejectEvent(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
NoteOpEvent lastAccessEvent = null;
for (OpFeatureEntry featureEntry : mFeatures.values()) {
NoteOpEvent lastFeatureAccessEvent = featureEntry.getLastRejectEvent(fromUidState,
toUidState, flags);
if (lastAccessEvent == null || (lastFeatureAccessEvent != null
&& lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
lastAccessEvent = lastFeatureAccessEvent;
}
}
return lastAccessEvent;
}
/**
* Return the last rejection time.
*
* @param fromUidState the lowest uid state to query
* @param toUidState the highest uid state to query (inclusive)
* @param flags The op flags
*
* @return the last rejection time (in milliseconds since epoch start (January 1, 1970
* 00:00:00.000 GMT - Gregorian)) or {@code -1}
*
* @see #getLastRejectTime(int)
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectBackgroundTime(int)
* @see #getLastRejectTime(int, int, int)
* @see OpFeatureEntry#getLastRejectTime(int, int, int)
*/
public long getLastRejectTime(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
NoteOpEvent lastEvent = getLastRejectEvent(fromUidState, toUidState, flags);
if (lastEvent == null) {
return -1;
}
return lastEvent.getNoteTime();
}
/**
* @return Whether the operation is running.
*/
public boolean isRunning() {
for (OpFeatureEntry opFeatureEntry : mFeatures.values()) {
if (opFeatureEntry.isRunning()) {
return true;
}
}
return false;
}
/**
* @deprecated Use {@link #getLastDuration(int)} instead
*/
@Deprecated
public long getDuration() {
return getLastDuration(OP_FLAGS_ALL);
}
/**
* Return the duration in milliseconds of the last the access.
*
* @param flags The op flags
*
* @return the duration in milliseconds or {@code -1}
*
* @see #getLastForegroundDuration(int)
* @see #getLastBackgroundDuration(int)
* @see #getLastDuration(int, int, int)
* @see OpFeatureEntry#getLastDuration(int)
*/
public long getLastDuration(@OpFlags int flags) {
return getLastDuration(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
}
/**
* Return the duration in milliseconds of the last foreground access.
*
* @param flags The op flags
*
* @return the duration in milliseconds or {@code -1}
*
* @see #getLastDuration(int)
* @see #getLastBackgroundDuration(int)
* @see #getLastDuration(int, int, int)
* @see OpFeatureEntry#getLastForegroundDuration(int)
*/
public long getLastForegroundDuration(@OpFlags int flags) {
return getLastDuration(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
flags);
}
/**
* Return the duration in milliseconds of the last background access.
*
* @param flags The op flags
*
* @return the duration in milliseconds or {@code -1}
*
* @see #getLastDuration(int)
* @see #getLastForegroundDuration(int)
* @see #getLastDuration(int, int, int)
* @see OpFeatureEntry#getLastBackgroundDuration(int)
*/
public long getLastBackgroundDuration(@OpFlags int flags) {
return getLastDuration(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
flags);
}
/**
* Return the duration in milliseconds of the last access.
*
* @param fromUidState The lowest UID state for which to query
* @param toUidState The highest UID state for which to query (inclusive)
* @param flags The op flags
*
* @return the duration in milliseconds or {@code -1}
*
* @see #getLastDuration(int)
* @see #getLastForegroundDuration(int)
* @see #getLastBackgroundDuration(int)
* @see OpFeatureEntry#getLastDuration(int, int, int)
*/
public long getLastDuration(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);
if (lastEvent == null) {
return -1;
}
return lastEvent.getDuration();
}
/**
* @deprecated Use {@link #getLastProxyInfo(int)} instead
*/
@Deprecated
public int getProxyUid() {
OpEventProxyInfo proxy = getLastProxyInfo(OP_FLAGS_ALL);
if (proxy == null) {
return Process.INVALID_UID;
}
return proxy.getUid();
}
/**
* @deprecated Use {@link #getLastProxyInfo(int)} instead
*/
@Deprecated
public int getProxyUid(@UidState int uidState, @OpFlags int flags) {
OpEventProxyInfo proxy = getLastProxyInfo(uidState, uidState, flags);
if (proxy == null) {
return Process.INVALID_UID;
}
return proxy.getUid();
}
/**
* @deprecated Use {@link #getLastProxyInfo(int)} instead
*/
@Deprecated
public @Nullable String getProxyPackageName() {
OpEventProxyInfo proxy = getLastProxyInfo(OP_FLAGS_ALL);
if (proxy == null) {
return null;
}
return proxy.getPackageName();
}
/**
* @deprecated Use {@link #getLastProxyInfo(int)} instead
*/
@Deprecated
public @Nullable String getProxyPackageName(@UidState int uidState, @OpFlags int flags) {
OpEventProxyInfo proxy = getLastProxyInfo(uidState, uidState, flags);
if (proxy == null) {
return null;
}
return proxy.getPackageName();
}
/**
* Gets the proxy info of the app that performed the last access on behalf of this app and
* as a result blamed the op on this app.
*
* @param flags The op flags
*
* @return The proxy name or {@code null}
*
* @see #getLastForegroundProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
* @see #getLastProxyInfo(int, int, int)
* @see OpFeatureEntry#getLastProxyInfo(int)
*/
public @Nullable OpEventProxyInfo getLastProxyInfo(@OpFlags int flags) {
return getLastProxyInfo(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
}
/**
* Gets the proxy info of the app that performed the last foreground access on behalf of
* this app and as a result blamed the op on this app.
*
* @param flags The op flags
*
* @return The proxy name or {@code null}
*
* @see #getLastProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
* @see #getLastProxyInfo(int, int, int)
* @see OpFeatureEntry#getLastForegroundProxyInfo(int)
*/
public @Nullable OpEventProxyInfo getLastForegroundProxyInfo(@OpFlags int flags) {
return getLastProxyInfo(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
flags);
}
/**
* Gets the proxy info of the app that performed the last background access on behalf of
* this app and as a result blamed the op on this app.
*
* @param flags The op flags
*
* @return The proxy name or {@code null}
*
* @see #getLastProxyInfo(int)
* @see #getLastForegroundProxyInfo(int)
* @see #getLastProxyInfo(int, int, int)
* @see OpFeatureEntry#getLastBackgroundProxyInfo(int)
*/
public @Nullable OpEventProxyInfo getLastBackgroundProxyInfo(@OpFlags int flags) {
return getLastProxyInfo(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
flags);
}
/**
* Gets the proxy info of the app that performed the last access on behalf of this app and
* as a result blamed the op on this app.
*
* @param fromUidState The lowest UID state for which to query
* @param toUidState The highest UID state for which to query (inclusive)
* @param flags The op flags
*
* @return The proxy name or {@code null}
*
* @see #getLastProxyInfo(int)
* @see #getLastForegroundProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
* @see OpFeatureEntry#getLastProxyInfo(int, int, int)
*/
public @Nullable OpEventProxyInfo getLastProxyInfo(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
NoteOpEvent lastEvent = getLastAccessEvent(fromUidState, toUidState, flags);
if (lastEvent == null) {
return null;
}
return lastEvent.getProxy();
}
// Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/AppOpsManager.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
/**
* Creates a new OpEntry.
*
* @param op
* The code of the op
* @param mode
* The mode of the op
* @param features
* The features that have been used when checking the op
* @hide
*/
@DataClass.Generated.Member
public OpEntry(
@IntRange(from = 0, to = _NUM_OP - 1) int op,
@Mode int mode,
@NonNull Map<String,OpFeatureEntry> features) {
this.mOp = op;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOp,
"from", 0,
"to", _NUM_OP - 1);
this.mMode = mode;
com.android.internal.util.AnnotationValidations.validate(
Mode.class, null, mMode);
this.mFeatures = features;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mFeatures);
// onConstructed(); // You can define this method to get a callback
}
/**
* The mode of the op
*/
@DataClass.Generated.Member
public @Mode int getMode() {
return mMode;
}
/**
* The features that have been used when checking the op
*/
@DataClass.Generated.Member
public @NonNull Map<String,OpFeatureEntry> getFeatures() {
return mFeatures;
}
@Override
@DataClass.Generated.Member
public void writeToParcel(Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
dest.writeInt(mOp);
dest.writeInt(mMode);
dest.writeMap(mFeatures);
}
@Override
@DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
/* package-private */ OpEntry(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
int op = in.readInt();
int mode = in.readInt();
Map<String,OpFeatureEntry> features = new java.util.LinkedHashMap<>();
in.readMap(features, OpFeatureEntry.class.getClassLoader());
this.mOp = op;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOp,
"from", 0,
"to", _NUM_OP - 1);
this.mMode = mode;
com.android.internal.util.AnnotationValidations.validate(
Mode.class, null, mMode);
this.mFeatures = features;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mFeatures);
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<OpEntry> CREATOR
= new Parcelable.Creator<OpEntry>() {
@Override
public OpEntry[] newArray(int size) {
return new OpEntry[size];
}
@Override
public OpEntry createFromParcel(@NonNull Parcel in) {
return new OpEntry(in);
}
};
/*
@DataClass.Generated(
time = 1574809856259L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final @android.app.Mode int mMode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.app.OpFeatureEntry> mFeatures\npublic @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getOpStr()}\") int getOp()\npublic @android.annotation.NonNull java.lang.String getOpStr()\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getAccessTime(int, int)}\") long getTime()\npublic @java.lang.Deprecated long getLastAccessTime(int)\npublic @java.lang.Deprecated long getLastAccessForegroundTime(int)\npublic @java.lang.Deprecated long getLastAccessBackgroundTime(int)\npublic @java.lang.Deprecated long getLastAccessTime(int,int,int)\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getLastRejectTime(int, int, int)}\") long getRejectTime()\npublic @java.lang.Deprecated long getLastRejectTime(int)\npublic @java.lang.Deprecated long getLastRejectForegroundTime(int)\npublic @java.lang.Deprecated long getLastRejectBackgroundTime(int)\npublic @java.lang.Deprecated long getLastRejectTime(int,int,int)\npublic long getAccessTime(int,int)\npublic long getRejectTime(int,int)\npublic boolean isRunning()\nprivate android.app.NoteOpEvent getLastAccessEvent(int,int,int)\npublic @java.lang.Deprecated long getDuration()\npublic @java.lang.Deprecated long getLastForegroundDuration(int)\npublic @java.lang.Deprecated long getLastBackgroundDuration(int)\npublic @java.lang.Deprecated long getLastDuration(int,int,int)\npublic @java.lang.Deprecated int getProxyUid()\npublic @java.lang.Deprecated @android.annotation.Nullable java.lang.String getProxyPackageName()\nprivate @android.app.UidState int getLastAccessUidStateForFlagsInStatesOfAllFeatures(int,int,int)\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\nprivate @android.app.UidState int getLastRejectUidStateForFlagsInStatesOfAllFeatures(int,int,int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic long getDuration(int,int)\npublic int getProxyUid(int,int)\nprivate int getProxyUid(int,int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\nprivate @android.annotation.Nullable java.lang.String getProxyPackageName(int,int,int)\nclass OpEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
*/
//@formatter:on
// End of generated code
}
/** @hide */
public interface HistoricalOpsVisitor {
void visitHistoricalOps(@NonNull HistoricalOps ops);
void visitHistoricalUidOps(@NonNull HistoricalUidOps ops);
void visitHistoricalPackageOps(@NonNull HistoricalPackageOps ops);
void visitHistoricalFeatureOps(@NonNull HistoricalFeatureOps ops);
void visitHistoricalOp(@NonNull HistoricalOp ops);
}
/**
* Specifies what parameters to filter historical appop requests for
*
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "FILTER_BY_" }, value = {
FILTER_BY_UID,
FILTER_BY_PACKAGE_NAME,
FILTER_BY_FEATURE_ID,
FILTER_BY_OP_NAMES
})
public @interface HistoricalOpsRequestFilter {}
/**
* Filter historical appop request by uid.
*
* @hide
*/
public static final int FILTER_BY_UID = 1<<0;
/**
* Filter historical appop request by package name.
*
* @hide
*/
public static final int FILTER_BY_PACKAGE_NAME = 1<<1;
/**
* Filter historical appop request by feature id.
*
* @hide
*/
public static final int FILTER_BY_FEATURE_ID = 1<<2;
/**
* Filter historical appop request by op names.
*
* @hide
*/
public static final int FILTER_BY_OP_NAMES = 1<<3;
/**
* Request for getting historical app op usage. The request acts
* as a filtering criteria when querying historical op usage.
*
* @hide
*/
@Immutable
@TestApi
@SystemApi
public static final class HistoricalOpsRequest {
private final int mUid;
private final @Nullable String mPackageName;
private final @Nullable String mFeatureId;
private final @Nullable List<String> mOpNames;
private final @HistoricalOpsRequestFilter int mFilter;
private final long mBeginTimeMillis;
private final long mEndTimeMillis;
private final @OpFlags int mFlags;
private HistoricalOpsRequest(int uid, @Nullable String packageName,
@Nullable String featureId, @Nullable List<String> opNames,
@HistoricalOpsRequestFilter int filter, long beginTimeMillis,
long endTimeMillis, @OpFlags int flags) {
mUid = uid;
mPackageName = packageName;
mFeatureId = featureId;
mOpNames = opNames;
mFilter = filter;
mBeginTimeMillis = beginTimeMillis;
mEndTimeMillis = endTimeMillis;
mFlags = flags;
}
/**
* Builder for creating a {@link HistoricalOpsRequest}.
*
* @hide
*/
@TestApi
@SystemApi
public static final class Builder {
private int mUid = Process.INVALID_UID;
private @Nullable String mPackageName;
private @Nullable String mFeatureId;
private @Nullable List<String> mOpNames;
private @HistoricalOpsRequestFilter int mFilter;
private final long mBeginTimeMillis;
private final long mEndTimeMillis;
private @OpFlags int mFlags = OP_FLAGS_ALL;
/**
* Creates a new builder.
*
* @param beginTimeMillis The beginning of the interval in milliseconds since
* epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be non
* negative.
* @param endTimeMillis The end of the interval in milliseconds since
* epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian). Must be after
* {@code beginTimeMillis}. Pass {@link Long#MAX_VALUE} to get the most recent
* history including ops that happen while this call is in flight.
*/
public Builder(long beginTimeMillis, long endTimeMillis) {
Preconditions.checkArgument(beginTimeMillis >= 0 && beginTimeMillis < endTimeMillis,
"beginTimeMillis must be non negative and lesser than endTimeMillis");
mBeginTimeMillis = beginTimeMillis;
mEndTimeMillis = endTimeMillis;
}
/**
* Sets the UID to query for.
*
* @param uid The uid. Pass {@link android.os.Process#INVALID_UID} for any uid.
* @return This builder.
*/
public @NonNull Builder setUid(int uid) {
Preconditions.checkArgument(uid == Process.INVALID_UID || uid >= 0,
"uid must be " + Process.INVALID_UID + " or non negative");
mUid = uid;
if (uid == Process.INVALID_UID) {
mFilter &= ~FILTER_BY_UID;
} else {
mFilter |= FILTER_BY_UID;
}
return this;
}
/**
* Sets the package to query for.
*
* @param packageName The package name. <code>Null</code> for any package.
* @return This builder.
*/
public @NonNull Builder setPackageName(@Nullable String packageName) {
mPackageName = packageName;
if (packageName == null) {
mFilter &= ~FILTER_BY_PACKAGE_NAME;
} else {
mFilter |= FILTER_BY_PACKAGE_NAME;
}
return this;
}
/**
* Sets the feature id to query for.
*
* @param featureId The id of the feature.
* @return This builder.
*/
public @NonNull Builder setFeatureId(@Nullable String featureId) {
mFeatureId = featureId;
mFilter |= FILTER_BY_FEATURE_ID;
return this;
}
/**
* Sets the op names to query for.
*
* @param opNames The op names. <code>Null</code> for any op.
* @return This builder.
*/
public @NonNull Builder setOpNames(@Nullable List<String> opNames) {
if (opNames != null) {
final int opCount = opNames.size();
for (int i = 0; i < opCount; i++) {
Preconditions.checkArgument(AppOpsManager.strOpToOp(
opNames.get(i)) != AppOpsManager.OP_NONE);
}
}
mOpNames = opNames;
if (mOpNames == null) {
mFilter &= ~FILTER_BY_OP_NAMES;
} else {
mFilter |= FILTER_BY_OP_NAMES;
}
return this;
}
/**
* Sets the op flags to query for. The flags specify the type of
* op data being queried.
*
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
* {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
* for any flag.
* @return This builder.
*/
public @NonNull Builder setFlags(@OpFlags int flags) {
Preconditions.checkFlagsArgument(flags, OP_FLAGS_ALL);
mFlags = flags;
return this;
}
/**
* @return a new {@link HistoricalOpsRequest}.
*/
public @NonNull HistoricalOpsRequest build() {
return new HistoricalOpsRequest(mUid, mPackageName, mFeatureId, mOpNames,
mFilter, mBeginTimeMillis, mEndTimeMillis, mFlags);
}
}
}
/**
* This class represents historical app op state of all UIDs for a given time interval.
*
* @hide
*/
@TestApi
@SystemApi
public static final class HistoricalOps implements Parcelable {
private long mBeginTimeMillis;
private long mEndTimeMillis;
private @Nullable SparseArray<HistoricalUidOps> mHistoricalUidOps;
/** @hide */
@TestApi
public HistoricalOps(long beginTimeMillis, long endTimeMillis) {
Preconditions.checkState(beginTimeMillis <= endTimeMillis);
mBeginTimeMillis = beginTimeMillis;
mEndTimeMillis = endTimeMillis;
}
/** @hide */
public HistoricalOps(@NonNull HistoricalOps other) {
mBeginTimeMillis = other.mBeginTimeMillis;
mEndTimeMillis = other.mEndTimeMillis;
Preconditions.checkState(mBeginTimeMillis <= mEndTimeMillis);
if (other.mHistoricalUidOps != null) {
final int opCount = other.getUidCount();
for (int i = 0; i < opCount; i++) {
final HistoricalUidOps origOps = other.getUidOpsAt(i);
final HistoricalUidOps clonedOps = new HistoricalUidOps(origOps);
if (mHistoricalUidOps == null) {
mHistoricalUidOps = new SparseArray<>(opCount);
}
mHistoricalUidOps.put(clonedOps.getUid(), clonedOps);
}
}
}
private HistoricalOps(Parcel parcel) {
mBeginTimeMillis = parcel.readLong();
mEndTimeMillis = parcel.readLong();
final int[] uids = parcel.createIntArray();
if (!ArrayUtils.isEmpty(uids)) {
final ParceledListSlice<HistoricalUidOps> listSlice = parcel.readParcelable(
HistoricalOps.class.getClassLoader());
final List<HistoricalUidOps> uidOps = (listSlice != null)
? listSlice.getList() : null;
if (uidOps == null) {
return;
}
for (int i = 0; i < uids.length; i++) {
if (mHistoricalUidOps == null) {
mHistoricalUidOps = new SparseArray<>();
}
mHistoricalUidOps.put(uids[i], uidOps.get(i));
}
}
}
/**
* Splice a piece from the beginning of these ops.
*
* @param splicePoint The fraction of the data to be spliced off.
*
* @hide
*/
public @NonNull HistoricalOps spliceFromBeginning(double splicePoint) {
return splice(splicePoint, true);
}
/**
* Splice a piece from the end of these ops.
*
* @param fractionToRemove The fraction of the data to be spliced off.
*
* @hide
*/
public @NonNull HistoricalOps spliceFromEnd(double fractionToRemove) {
return splice(fractionToRemove, false);
}
/**
* Splice a piece from the beginning or end of these ops.
*
* @param fractionToRemove The fraction of the data to be spliced off.
* @param beginning Whether to splice off the beginning or the end.
*
* @return The spliced off part.
*
* @hide
*/
private @Nullable HistoricalOps splice(double fractionToRemove, boolean beginning) {
final long spliceBeginTimeMills;
final long spliceEndTimeMills;
if (beginning) {
spliceBeginTimeMills = mBeginTimeMillis;
spliceEndTimeMills = (long) (mBeginTimeMillis
+ getDurationMillis() * fractionToRemove);
mBeginTimeMillis = spliceEndTimeMills;
} else {
spliceBeginTimeMills = (long) (mEndTimeMillis
- getDurationMillis() * fractionToRemove);
spliceEndTimeMills = mEndTimeMillis;
mEndTimeMillis = spliceBeginTimeMills;
}
HistoricalOps splice = null;
final int uidCount = getUidCount();
for (int i = 0; i < uidCount; i++) {
final HistoricalUidOps origOps = getUidOpsAt(i);
final HistoricalUidOps spliceOps = origOps.splice(fractionToRemove);
if (spliceOps != null) {
if (splice == null) {
splice = new HistoricalOps(spliceBeginTimeMills, spliceEndTimeMills);
}
if (splice.mHistoricalUidOps == null) {
splice.mHistoricalUidOps = new SparseArray<>();
}
splice.mHistoricalUidOps.put(spliceOps.getUid(), spliceOps);
}
}
return splice;
}
/**
* Merge the passed ops into the current ones. The time interval is a
* union of the current and passed in one and the passed in data is
* folded into the data of this instance.
*
* @hide
*/
public void merge(@NonNull HistoricalOps other) {
mBeginTimeMillis = Math.min(mBeginTimeMillis, other.mBeginTimeMillis);
mEndTimeMillis = Math.max(mEndTimeMillis, other.mEndTimeMillis);
final int uidCount = other.getUidCount();
for (int i = 0; i < uidCount; i++) {
final HistoricalUidOps otherUidOps = other.getUidOpsAt(i);
final HistoricalUidOps thisUidOps = getUidOps(otherUidOps.getUid());
if (thisUidOps != null) {
thisUidOps.merge(otherUidOps);
} else {
if (mHistoricalUidOps == null) {
mHistoricalUidOps = new SparseArray<>();
}
mHistoricalUidOps.put(otherUidOps.getUid(), otherUidOps);
}
}
}
/**
* AppPermissionUsage the ops to leave only the data we filter for.
*
* @param uid Uid to filter for.
* @param packageName Package to filter for.
* @param featureId Package to filter for.
* @param opNames Ops to filter for.
* @param filter Which parameters to filter on.
* @param beginTimeMillis The begin time to filter for or {@link Long#MIN_VALUE} for all.
* @param endTimeMillis The end time to filter for or {@link Long#MAX_VALUE} for all.
*
* @hide
*/
public void filter(int uid, @Nullable String packageName, @Nullable String featureId,
@Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
long beginTimeMillis, long endTimeMillis) {
final long durationMillis = getDurationMillis();
mBeginTimeMillis = Math.max(mBeginTimeMillis, beginTimeMillis);
mEndTimeMillis = Math.min(mEndTimeMillis, endTimeMillis);
final double scaleFactor = Math.min((double) (endTimeMillis - beginTimeMillis)
/ (double) durationMillis, 1);
final int uidCount = getUidCount();
for (int i = uidCount - 1; i >= 0; i--) {
final HistoricalUidOps uidOp = mHistoricalUidOps.valueAt(i);
if ((filter & FILTER_BY_UID) != 0 && uid != uidOp.getUid()) {
mHistoricalUidOps.removeAt(i);
} else {
uidOp.filter(packageName, featureId, opNames, filter, scaleFactor);
}
}
}
/** @hide */
public boolean isEmpty() {
if (getBeginTimeMillis() >= getEndTimeMillis()) {
return true;
}
final int uidCount = getUidCount();
for (int i = uidCount - 1; i >= 0; i--) {
final HistoricalUidOps uidOp = mHistoricalUidOps.valueAt(i);
if (!uidOp.isEmpty()) {
return false;
}
}
return true;
}
/** @hide */
public long getDurationMillis() {
return mEndTimeMillis - mBeginTimeMillis;
}
/** @hide */
@TestApi
public void increaseAccessCount(int opCode, int uid, @NonNull String packageName,
@Nullable String featureId, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalUidOps(uid).increaseAccessCount(opCode,
packageName, featureId, uidState, flags, increment);
}
/** @hide */
@TestApi
public void increaseRejectCount(int opCode, int uid, @NonNull String packageName,
@Nullable String featureId, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalUidOps(uid).increaseRejectCount(opCode,
packageName, featureId, uidState, flags, increment);
}
/** @hide */
@TestApi
public void increaseAccessDuration(int opCode, int uid, @NonNull String packageName,
@Nullable String featureId, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalUidOps(uid).increaseAccessDuration(opCode,
packageName, featureId, uidState, flags, increment);
}
/** @hide */
@TestApi
public void offsetBeginAndEndTime(long offsetMillis) {
mBeginTimeMillis += offsetMillis;
mEndTimeMillis += offsetMillis;
}
/** @hide */
public void setBeginAndEndTime(long beginTimeMillis, long endTimeMillis) {
mBeginTimeMillis = beginTimeMillis;
mEndTimeMillis = endTimeMillis;
}
/** @hide */
public void setBeginTime(long beginTimeMillis) {
mBeginTimeMillis = beginTimeMillis;
}
/** @hide */
public void setEndTime(long endTimeMillis) {
mEndTimeMillis = endTimeMillis;
}
/**
* @return The beginning of the interval in milliseconds since
* epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
*/
public long getBeginTimeMillis() {
return mBeginTimeMillis;
}
/**
* @return The end of the interval in milliseconds since
* epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
*/
public long getEndTimeMillis() {
return mEndTimeMillis;
}
/**
* Gets number of UIDs with historical ops.
*
* @return The number of UIDs with historical ops.
*
* @see #getUidOpsAt(int)
*/
public @IntRange(from = 0) int getUidCount() {
if (mHistoricalUidOps == null) {
return 0;
}
return mHistoricalUidOps.size();
}
/**
* Gets the historical UID ops at a given index.
*
* @param index The index.
*
* @return The historical UID ops at the given index.
*
* @see #getUidCount()
*/
public @NonNull HistoricalUidOps getUidOpsAt(@IntRange(from = 0) int index) {
if (mHistoricalUidOps == null) {
throw new IndexOutOfBoundsException();
}
return mHistoricalUidOps.valueAt(index);
}
/**
* Gets the historical UID ops for a given UID.
*
* @param uid The UID.
*
* @return The historical ops for the UID.
*/
public @Nullable HistoricalUidOps getUidOps(int uid) {
if (mHistoricalUidOps == null) {
return null;
}
return mHistoricalUidOps.get(uid);
}
/** @hide */
public void clearHistory(int uid, @NonNull String packageName) {
HistoricalUidOps historicalUidOps = getOrCreateHistoricalUidOps(uid);
historicalUidOps.clearHistory(packageName);
if (historicalUidOps.isEmpty()) {
mHistoricalUidOps.remove(uid);
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeLong(mBeginTimeMillis);
parcel.writeLong(mEndTimeMillis);
if (mHistoricalUidOps != null) {
final int uidCount = mHistoricalUidOps.size();
parcel.writeInt(uidCount);
for (int i = 0; i < uidCount; i++) {
parcel.writeInt(mHistoricalUidOps.keyAt(i));
}
final List<HistoricalUidOps> opsList = new ArrayList<>(uidCount);
for (int i = 0; i < uidCount; i++) {
opsList.add(mHistoricalUidOps.valueAt(i));
}
parcel.writeParcelable(new ParceledListSlice<>(opsList), flags);
} else {
parcel.writeInt(-1);
}
}
/**
* Accepts a visitor to traverse the ops tree.
*
* @param visitor The visitor.
*
* @hide
*/
public void accept(@NonNull HistoricalOpsVisitor visitor) {
visitor.visitHistoricalOps(this);
final int uidCount = getUidCount();
for (int i = 0; i < uidCount; i++) {
getUidOpsAt(i).accept(visitor);
}
}
private @NonNull HistoricalUidOps getOrCreateHistoricalUidOps(int uid) {
if (mHistoricalUidOps == null) {
mHistoricalUidOps = new SparseArray<>();
}
HistoricalUidOps historicalUidOp = mHistoricalUidOps.get(uid);
if (historicalUidOp == null) {
historicalUidOp = new HistoricalUidOps(uid);
mHistoricalUidOps.put(uid, historicalUidOp);
}
return historicalUidOp;
}
/**
* @return Rounded value up at the 0.5 boundary.
*
* @hide
*/
public static double round(double value) {
final BigDecimal decimalScale = new BigDecimal(value);
return decimalScale.setScale(0, RoundingMode.HALF_UP).doubleValue();
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final HistoricalOps other = (HistoricalOps) obj;
if (mBeginTimeMillis != other.mBeginTimeMillis) {
return false;
}
if (mEndTimeMillis != other.mEndTimeMillis) {
return false;
}
if (mHistoricalUidOps == null) {
if (other.mHistoricalUidOps != null) {
return false;
}
} else if (!mHistoricalUidOps.equals(other.mHistoricalUidOps)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = (int) (mBeginTimeMillis ^ (mBeginTimeMillis >>> 32));
result = 31 * result + mHistoricalUidOps.hashCode();
return result;
}
@NonNull
@Override
public String toString() {
return getClass().getSimpleName() + "[from:"
+ mBeginTimeMillis + " to:" + mEndTimeMillis + "]";
}
public static final @android.annotation.NonNull Creator<HistoricalOps> CREATOR = new Creator<HistoricalOps>() {
@Override
public @NonNull HistoricalOps createFromParcel(@NonNull Parcel parcel) {
return new HistoricalOps(parcel);
}
@Override
public @NonNull HistoricalOps[] newArray(int size) {
return new HistoricalOps[size];
}
};
}
/**
* This class represents historical app op state for a UID.
*
* @hide
*/
@TestApi
@SystemApi
public static final class HistoricalUidOps implements Parcelable {
private final int mUid;
private @Nullable ArrayMap<String, HistoricalPackageOps> mHistoricalPackageOps;
/** @hide */
public HistoricalUidOps(int uid) {
mUid = uid;
}
private HistoricalUidOps(@NonNull HistoricalUidOps other) {
mUid = other.mUid;
final int opCount = other.getPackageCount();
for (int i = 0; i < opCount; i++) {
final HistoricalPackageOps origOps = other.getPackageOpsAt(i);
final HistoricalPackageOps cloneOps = new HistoricalPackageOps(origOps);
if (mHistoricalPackageOps == null) {
mHistoricalPackageOps = new ArrayMap<>(opCount);
}
mHistoricalPackageOps.put(cloneOps.getPackageName(), cloneOps);
}
}
private HistoricalUidOps(@NonNull Parcel parcel) {
// No arg check since we always read from a trusted source.
mUid = parcel.readInt();
mHistoricalPackageOps = parcel.createTypedArrayMap(HistoricalPackageOps.CREATOR);
}
private @Nullable HistoricalUidOps splice(double fractionToRemove) {
HistoricalUidOps splice = null;
final int packageCount = getPackageCount();
for (int i = 0; i < packageCount; i++) {
final HistoricalPackageOps origOps = getPackageOpsAt(i);
final HistoricalPackageOps spliceOps = origOps.splice(fractionToRemove);
if (spliceOps != null) {
if (splice == null) {
splice = new HistoricalUidOps(mUid);
}
if (splice.mHistoricalPackageOps == null) {
splice.mHistoricalPackageOps = new ArrayMap<>();
}
splice.mHistoricalPackageOps.put(spliceOps.getPackageName(), spliceOps);
}
}
return splice;
}
private void merge(@NonNull HistoricalUidOps other) {
final int packageCount = other.getPackageCount();
for (int i = 0; i < packageCount; i++) {
final HistoricalPackageOps otherPackageOps = other.getPackageOpsAt(i);
final HistoricalPackageOps thisPackageOps = getPackageOps(
otherPackageOps.getPackageName());
if (thisPackageOps != null) {
thisPackageOps.merge(otherPackageOps);
} else {
if (mHistoricalPackageOps == null) {
mHistoricalPackageOps = new ArrayMap<>();
}
mHistoricalPackageOps.put(otherPackageOps.getPackageName(), otherPackageOps);
}
}
}
private void filter(@Nullable String packageName, @Nullable String featureId,
@Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
double fractionToRemove) {
final int packageCount = getPackageCount();
for (int i = packageCount - 1; i >= 0; i--) {
final HistoricalPackageOps packageOps = getPackageOpsAt(i);
if ((filter & FILTER_BY_PACKAGE_NAME) != 0 && !packageName.equals(
packageOps.getPackageName())) {
mHistoricalPackageOps.removeAt(i);
} else {
packageOps.filter(featureId, opNames, filter, fractionToRemove);
}
}
}
private boolean isEmpty() {
final int packageCount = getPackageCount();
for (int i = packageCount - 1; i >= 0; i--) {
final HistoricalPackageOps packageOps = mHistoricalPackageOps.valueAt(i);
if (!packageOps.isEmpty()) {
return false;
}
}
return true;
}
private void increaseAccessCount(int opCode, @NonNull String packageName,
@Nullable String featureId, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalPackageOps(packageName).increaseAccessCount(
opCode, featureId, uidState, flags, increment);
}
private void increaseRejectCount(int opCode, @NonNull String packageName,
@Nullable String featureId, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalPackageOps(packageName).increaseRejectCount(
opCode, featureId, uidState, flags, increment);
}
private void increaseAccessDuration(int opCode, @NonNull String packageName,
@Nullable String featureId, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalPackageOps(packageName).increaseAccessDuration(
opCode, featureId, uidState, flags, increment);
}
/**
* @return The UID for which the data is related.
*/
public int getUid() {
return mUid;
}
/**
* Gets number of packages with historical ops.
*
* @return The number of packages with historical ops.
*
* @see #getPackageOpsAt(int)
*/
public @IntRange(from = 0) int getPackageCount() {
if (mHistoricalPackageOps == null) {
return 0;
}
return mHistoricalPackageOps.size();
}
/**
* Gets the historical package ops at a given index.
*
* @param index The index.
*
* @return The historical package ops at the given index.
*
* @see #getPackageCount()
*/
public @NonNull HistoricalPackageOps getPackageOpsAt(@IntRange(from = 0) int index) {
if (mHistoricalPackageOps == null) {
throw new IndexOutOfBoundsException();
}
return mHistoricalPackageOps.valueAt(index);
}
/**
* Gets the historical package ops for a given package.
*
* @param packageName The package.
*
* @return The historical ops for the package.
*/
public @Nullable HistoricalPackageOps getPackageOps(@NonNull String packageName) {
if (mHistoricalPackageOps == null) {
return null;
}
return mHistoricalPackageOps.get(packageName);
}
private void clearHistory(@NonNull String packageName) {
if (mHistoricalPackageOps != null) {
mHistoricalPackageOps.remove(packageName);
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mUid);
parcel.writeTypedArrayMap(mHistoricalPackageOps, flags);
}
private void accept(@NonNull HistoricalOpsVisitor visitor) {
visitor.visitHistoricalUidOps(this);
final int packageCount = getPackageCount();
for (int i = 0; i < packageCount; i++) {
getPackageOpsAt(i).accept(visitor);
}
}
private @NonNull HistoricalPackageOps getOrCreateHistoricalPackageOps(
@NonNull String packageName) {
if (mHistoricalPackageOps == null) {
mHistoricalPackageOps = new ArrayMap<>();
}
HistoricalPackageOps historicalPackageOp = mHistoricalPackageOps.get(packageName);
if (historicalPackageOp == null) {
historicalPackageOp = new HistoricalPackageOps(packageName);
mHistoricalPackageOps.put(packageName, historicalPackageOp);
}
return historicalPackageOp;
}
public static final @android.annotation.NonNull Creator<HistoricalUidOps> CREATOR = new Creator<HistoricalUidOps>() {
@Override
public @NonNull HistoricalUidOps createFromParcel(@NonNull Parcel parcel) {
return new HistoricalUidOps(parcel);
}
@Override
public @NonNull HistoricalUidOps[] newArray(int size) {
return new HistoricalUidOps[size];
}
};
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final HistoricalUidOps other = (HistoricalUidOps) obj;
if (mUid != other.mUid) {
return false;
}
if (mHistoricalPackageOps == null) {
if (other.mHistoricalPackageOps != null) {
return false;
}
} else if (!mHistoricalPackageOps.equals(other.mHistoricalPackageOps)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = mUid;
result = 31 * result + (mHistoricalPackageOps != null
? mHistoricalPackageOps.hashCode() : 0);
return result;
}
}
/**
* This class represents historical app op information about a package.
*
* @hide
*/
@TestApi
@SystemApi
public static final class HistoricalPackageOps implements Parcelable {
private final @NonNull String mPackageName;
private @Nullable ArrayMap<String, HistoricalFeatureOps> mHistoricalFeatureOps;
/** @hide */
public HistoricalPackageOps(@NonNull String packageName) {
mPackageName = packageName;
}
private HistoricalPackageOps(@NonNull HistoricalPackageOps other) {
mPackageName = other.mPackageName;
final int opCount = other.getFeatureCount();
for (int i = 0; i < opCount; i++) {
final HistoricalFeatureOps origOps = other.getFeatureOpsAt(i);
final HistoricalFeatureOps cloneOps = new HistoricalFeatureOps(origOps);
if (mHistoricalFeatureOps == null) {
mHistoricalFeatureOps = new ArrayMap<>(opCount);
}
mHistoricalFeatureOps.put(cloneOps.getFeatureId(), cloneOps);
}
}
private HistoricalPackageOps(@NonNull Parcel parcel) {
mPackageName = parcel.readString();
mHistoricalFeatureOps = parcel.createTypedArrayMap(HistoricalFeatureOps.CREATOR);
}
private @Nullable HistoricalPackageOps splice(double fractionToRemove) {
HistoricalPackageOps splice = null;
final int featureCount = getFeatureCount();
for (int i = 0; i < featureCount; i++) {
final HistoricalFeatureOps origOps = getFeatureOpsAt(i);
final HistoricalFeatureOps spliceOps = origOps.splice(fractionToRemove);
if (spliceOps != null) {
if (splice == null) {
splice = new HistoricalPackageOps(mPackageName);
}
if (splice.mHistoricalFeatureOps == null) {
splice.mHistoricalFeatureOps = new ArrayMap<>();
}
splice.mHistoricalFeatureOps.put(spliceOps.getFeatureId(), spliceOps);
}
}
return splice;
}
private void merge(@NonNull HistoricalPackageOps other) {
final int featureCount = other.getFeatureCount();
for (int i = 0; i < featureCount; i++) {
final HistoricalFeatureOps otherFeatureOps = other.getFeatureOpsAt(i);
final HistoricalFeatureOps thisFeatureOps = getFeatureOps(
otherFeatureOps.getFeatureId());
if (thisFeatureOps != null) {
thisFeatureOps.merge(otherFeatureOps);
} else {
if (mHistoricalFeatureOps == null) {
mHistoricalFeatureOps = new ArrayMap<>();
}
mHistoricalFeatureOps.put(otherFeatureOps.getFeatureId(), otherFeatureOps);
}
}
}
private void filter(@Nullable String featureId, @Nullable String[] opNames,
@HistoricalOpsRequestFilter int filter, double fractionToRemove) {
final int featureCount = getFeatureCount();
for (int i = featureCount - 1; i >= 0; i--) {
final HistoricalFeatureOps featureOps = getFeatureOpsAt(i);
if ((filter & FILTER_BY_FEATURE_ID) != 0 && !Objects.equals(featureId,
featureOps.getFeatureId())) {
mHistoricalFeatureOps.removeAt(i);
} else {
featureOps.filter(opNames, filter, fractionToRemove);
}
}
}
private void accept(@NonNull HistoricalOpsVisitor visitor) {
visitor.visitHistoricalPackageOps(this);
final int featureCount = getFeatureCount();
for (int i = 0; i < featureCount; i++) {
getFeatureOpsAt(i).accept(visitor);
}
}
private boolean isEmpty() {
final int featureCount = getFeatureCount();
for (int i = featureCount - 1; i >= 0; i--) {
final HistoricalFeatureOps featureOps = mHistoricalFeatureOps.valueAt(i);
if (!featureOps.isEmpty()) {
return false;
}
}
return true;
}
private void increaseAccessCount(int opCode, @Nullable String featureId,
@UidState int uidState, @OpFlags int flags, long increment) {
getOrCreateHistoricalFeatureOps(featureId).increaseAccessCount(
opCode, uidState, flags, increment);
}
private void increaseRejectCount(int opCode, @Nullable String featureId,
@UidState int uidState, @OpFlags int flags, long increment) {
getOrCreateHistoricalFeatureOps(featureId).increaseRejectCount(
opCode, uidState, flags, increment);
}
private void increaseAccessDuration(int opCode, @Nullable String featureId,
@UidState int uidState, @OpFlags int flags, long increment) {
getOrCreateHistoricalFeatureOps(featureId).increaseAccessDuration(
opCode, uidState, flags, increment);
}
/**
* Gets the package name which the data represents.
*
* @return The package name which the data represents.
*/
public @NonNull String getPackageName() {
return mPackageName;
}
private @NonNull HistoricalFeatureOps getOrCreateHistoricalFeatureOps(
@Nullable String featureId) {
if (mHistoricalFeatureOps == null) {
mHistoricalFeatureOps = new ArrayMap<>();
}
HistoricalFeatureOps historicalFeatureOp = mHistoricalFeatureOps.get(featureId);
if (historicalFeatureOp == null) {
historicalFeatureOp = new HistoricalFeatureOps(featureId);
mHistoricalFeatureOps.put(featureId, historicalFeatureOp);
}
return historicalFeatureOp;
}
/**
* Gets number historical app ops.
*
* @return The number historical app ops.
* @see #getOpAt(int)
*/
public @IntRange(from = 0) int getOpCount() {
int numOps = 0;
int numFeatures = getFeatureCount();
for (int code = 0; code < _NUM_OP; code++) {
String opName = opToPublicName(code);
for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
if (getFeatureOpsAt(featureNum).getOp(opName) != null) {
numOps++;
break;
}
}
}
return numOps;
}
/**
* Gets the historical op at a given index.
*
* <p>This combines the counts from all features.
*
* @param index The index to lookup.
* @return The op at the given index.
* @see #getOpCount()
*/
public @NonNull HistoricalOp getOpAt(@IntRange(from = 0) int index) {
int numOpsFound = 0;
int numFeatures = getFeatureCount();
for (int code = 0; code < _NUM_OP; code++) {
String opName = opToPublicName(code);
for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
if (getFeatureOpsAt(featureNum).getOp(opName) != null) {
if (numOpsFound == index) {
return getOp(opName);
} else {
numOpsFound++;
break;
}
}
}
}
throw new IndexOutOfBoundsException();
}
/**
* Gets the historical entry for a given op name.
*
* <p>This combines the counts from all features.
*
* @param opName The op name.
* @return The historical entry for that op name.
*/
public @Nullable HistoricalOp getOp(@NonNull String opName) {
if (mHistoricalFeatureOps == null) {
return null;
}
HistoricalOp combinedOp = null;
int numFeatures = getFeatureCount();
for (int i = 0; i < numFeatures; i++) {
HistoricalOp featureOp = getFeatureOpsAt(i).getOp(opName);
if (featureOp != null) {
if (combinedOp == null) {
combinedOp = new HistoricalOp(featureOp);
} else {
combinedOp.merge(featureOp);
}
}
}
return combinedOp;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeString(mPackageName);
parcel.writeTypedArrayMap(mHistoricalFeatureOps, flags);
}
public static final @android.annotation.NonNull Creator<HistoricalPackageOps> CREATOR =
new Creator<HistoricalPackageOps>() {
@Override
public @NonNull HistoricalPackageOps createFromParcel(@NonNull Parcel parcel) {
return new HistoricalPackageOps(parcel);
}
@Override
public @NonNull HistoricalPackageOps[] newArray(int size) {
return new HistoricalPackageOps[size];
}
};
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final HistoricalPackageOps other = (HistoricalPackageOps) obj;
if (!mPackageName.equals(other.mPackageName)) {
return false;
}
if (mHistoricalFeatureOps == null) {
if (other.mHistoricalFeatureOps != null) {
return false;
}
} else if (!mHistoricalFeatureOps.equals(other.mHistoricalFeatureOps)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = mPackageName != null ? mPackageName.hashCode() : 0;
result = 31 * result + (mHistoricalFeatureOps != null ? mHistoricalFeatureOps.hashCode()
: 0);
return result;
}
/**
* Gets number of feature with historical ops.
*
* @return The number of feature with historical ops.
*
* @see #getFeatureOpsAt(int)
*/
public @IntRange(from = 0) int getFeatureCount() {
if (mHistoricalFeatureOps == null) {
return 0;
}
return mHistoricalFeatureOps.size();
}
/**
* Gets the historical feature ops at a given index.
*
* @param index The index.
*
* @return The historical feature ops at the given index.
*
* @see #getFeatureCount()
*/
public @NonNull HistoricalFeatureOps getFeatureOpsAt(@IntRange(from = 0) int index) {
if (mHistoricalFeatureOps == null) {
throw new IndexOutOfBoundsException();
}
return mHistoricalFeatureOps.valueAt(index);
}
/**
* Gets the historical feature ops for a given feature.
*
* @param featureId The feature id.
*
* @return The historical ops for the feature.
*/
public @Nullable HistoricalFeatureOps getFeatureOps(@NonNull String featureId) {
if (mHistoricalFeatureOps == null) {
return null;
}
return mHistoricalFeatureOps.get(featureId);
}
}
/**
* This class represents historical app op information about a feature in a package.
*
* @hide
*/
@TestApi
@SystemApi
/* codegen verifier cannot deal with nested class parameters
@DataClass(genHiddenConstructor = true,
genEqualsHashCode = true, genHiddenCopyConstructor = true) */
@DataClass.Suppress("getHistoricalOps")
public static final class HistoricalFeatureOps implements Parcelable {
/** Id of the {@link Context#createFeatureContext feature} in the package */
private final @Nullable String mFeatureId;
/** Ops for this feature */
private @Nullable ArrayMap<String, HistoricalOp> mHistoricalOps;
/** @hide */
public HistoricalFeatureOps(@NonNull String featureId) {
mFeatureId = featureId;
}
private HistoricalFeatureOps(@NonNull HistoricalFeatureOps other) {
mFeatureId = other.mFeatureId;
final int opCount = other.getOpCount();
for (int i = 0; i < opCount; i++) {
final HistoricalOp origOp = other.getOpAt(i);
final HistoricalOp cloneOp = new HistoricalOp(origOp);
if (mHistoricalOps == null) {
mHistoricalOps = new ArrayMap<>(opCount);
}
mHistoricalOps.put(cloneOp.getOpName(), cloneOp);
}
}
private @Nullable HistoricalFeatureOps splice(double fractionToRemove) {
HistoricalFeatureOps splice = null;
final int opCount = getOpCount();
for (int i = 0; i < opCount; i++) {
final HistoricalOp origOps = getOpAt(i);
final HistoricalOp spliceOps = origOps.splice(fractionToRemove);
if (spliceOps != null) {
if (splice == null) {
splice = new HistoricalFeatureOps(mFeatureId, null);
}
if (splice.mHistoricalOps == null) {
splice.mHistoricalOps = new ArrayMap<>();
}
splice.mHistoricalOps.put(spliceOps.getOpName(), spliceOps);
}
}
return splice;
}
private void merge(@NonNull HistoricalFeatureOps other) {
final int opCount = other.getOpCount();
for (int i = 0; i < opCount; i++) {
final HistoricalOp otherOp = other.getOpAt(i);
final HistoricalOp thisOp = getOp(otherOp.getOpName());
if (thisOp != null) {
thisOp.merge(otherOp);
} else {
if (mHistoricalOps == null) {
mHistoricalOps = new ArrayMap<>();
}
mHistoricalOps.put(otherOp.getOpName(), otherOp);
}
}
}
private void filter(@Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
double scaleFactor) {
final int opCount = getOpCount();
for (int i = opCount - 1; i >= 0; i--) {
final HistoricalOp op = mHistoricalOps.valueAt(i);
if ((filter & FILTER_BY_OP_NAMES) != 0 && !ArrayUtils.contains(opNames,
op.getOpName())) {
mHistoricalOps.removeAt(i);
} else {
op.filter(scaleFactor);
}
}
}
private boolean isEmpty() {
final int opCount = getOpCount();
for (int i = opCount - 1; i >= 0; i--) {
final HistoricalOp op = mHistoricalOps.valueAt(i);
if (!op.isEmpty()) {
return false;
}
}
return true;
}
private void increaseAccessCount(int opCode, @UidState int uidState,
@OpFlags int flags, long increment) {
getOrCreateHistoricalOp(opCode).increaseAccessCount(uidState, flags, increment);
}
private void increaseRejectCount(int opCode, @UidState int uidState,
@OpFlags int flags, long increment) {
getOrCreateHistoricalOp(opCode).increaseRejectCount(uidState, flags, increment);
}
private void increaseAccessDuration(int opCode, @UidState int uidState,
@OpFlags int flags, long increment) {
getOrCreateHistoricalOp(opCode).increaseAccessDuration(uidState, flags, increment);
}
/**
* Gets number historical app ops.
*
* @return The number historical app ops.
* @see #getOpAt(int)
*/
public @IntRange(from = 0) int getOpCount() {
if (mHistoricalOps == null) {
return 0;
}
return mHistoricalOps.size();
}
/**
* Gets the historical op at a given index.
*
* @param index The index to lookup.
* @return The op at the given index.
* @see #getOpCount()
*/
public @NonNull HistoricalOp getOpAt(@IntRange(from = 0) int index) {
if (mHistoricalOps == null) {
throw new IndexOutOfBoundsException();
}
return mHistoricalOps.valueAt(index);
}
/**
* Gets the historical entry for a given op name.
*
* @param opName The op name.
* @return The historical entry for that op name.
*/
public @Nullable HistoricalOp getOp(@NonNull String opName) {
if (mHistoricalOps == null) {
return null;
}
return mHistoricalOps.get(opName);
}
private void accept(@NonNull HistoricalOpsVisitor visitor) {
visitor.visitHistoricalFeatureOps(this);
final int opCount = getOpCount();
for (int i = 0; i < opCount; i++) {
getOpAt(i).accept(visitor);
}
}
private @NonNull HistoricalOp getOrCreateHistoricalOp(int opCode) {
if (mHistoricalOps == null) {
mHistoricalOps = new ArrayMap<>();
}
final String opStr = sOpToString[opCode];
HistoricalOp op = mHistoricalOps.get(opStr);
if (op == null) {
op = new HistoricalOp(opCode);
mHistoricalOps.put(opStr, op);
}
return op;
}
// Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/AppOpsManager.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
/**
* Creates a new HistoricalFeatureOps.
*
* @param featureId
* Id of the {@link Context#createFeatureContext feature} in the package
* @param historicalOps
* Ops for this feature
* @hide
*/
@DataClass.Generated.Member
public HistoricalFeatureOps(
@Nullable String featureId,
@Nullable ArrayMap<String,HistoricalOp> historicalOps) {
this.mFeatureId = featureId;
this.mHistoricalOps = historicalOps;
// onConstructed(); // You can define this method to get a callback
}
/**
* Id of the {@link Context#createFeatureContext feature} in the package
*/
@DataClass.Generated.Member
public @Nullable String getFeatureId() {
return mFeatureId;
}
@Override
@DataClass.Generated.Member
public boolean equals(@Nullable Object o) {
// You can override field equality logic by defining either of the methods like:
// boolean fieldNameEquals(HistoricalFeatureOps other) { ... }
// boolean fieldNameEquals(FieldType otherValue) { ... }
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@SuppressWarnings("unchecked")
HistoricalFeatureOps that = (HistoricalFeatureOps) o;
//noinspection PointlessBooleanExpression
return true
&& Objects.equals(mFeatureId, that.mFeatureId)
&& Objects.equals(mHistoricalOps, that.mHistoricalOps);
}
@Override
@DataClass.Generated.Member
public int hashCode() {
// You can override field hashCode logic by defining methods like:
// int fieldNameHashCode() { ... }
int _hash = 1;
_hash = 31 * _hash + Objects.hashCode(mFeatureId);
_hash = 31 * _hash + Objects.hashCode(mHistoricalOps);
return _hash;
}
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
if (mFeatureId != null) flg |= 0x1;
if (mHistoricalOps != null) flg |= 0x2;
dest.writeByte(flg);
if (mFeatureId != null) dest.writeString(mFeatureId);
if (mHistoricalOps != null) dest.writeMap(mHistoricalOps);
}
@Override
@DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
/* package-private */ HistoricalFeatureOps(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
String featureId = (flg & 0x1) == 0 ? null : in.readString();
ArrayMap<String,HistoricalOp> historicalOps = null;
if ((flg & 0x2) != 0) {
historicalOps = new ArrayMap();
in.readMap(historicalOps, HistoricalOp.class.getClassLoader());
}
this.mFeatureId = featureId;
this.mHistoricalOps = historicalOps;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<HistoricalFeatureOps> CREATOR
= new Parcelable.Creator<HistoricalFeatureOps>() {
@Override
public HistoricalFeatureOps[] newArray(int size) {
return new HistoricalFeatureOps[size];
}
@Override
public HistoricalFeatureOps createFromParcel(@NonNull Parcel in) {
return new HistoricalFeatureOps(in);
}
};
/*
@DataClass.Generated(
time = 1578113234821L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
inputSignatures = "private final @android.annotation.Nullable java.lang.String mFeatureId\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.app.HistoricalOp> mHistoricalOps\nprivate @android.annotation.Nullable android.app.HistoricalFeatureOps splice(double)\nprivate void merge(android.app.HistoricalFeatureOps)\nprivate void filter(java.lang.String[],int,double)\nprivate boolean isEmpty()\nprivate void increaseAccessCount(int,int,int,long)\nprivate void increaseRejectCount(int,int,int,long)\nprivate void increaseAccessDuration(int,int,int,long)\npublic @android.annotation.IntRange(from=0L) int getOpCount()\npublic @android.annotation.NonNull android.app.HistoricalOp getOpAt(int)\npublic @android.annotation.Nullable android.app.HistoricalOp getOp(java.lang.String)\nprivate void accept(android.app.HistoricalOpsVisitor)\nprivate @android.annotation.NonNull android.app.HistoricalOp getOrCreateHistoricalOp(int)\nclass HistoricalFeatureOps extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true, genHiddenCopyConstructor=true)")
@Deprecated
private void __metadata() {}
*/
//@formatter:on
// End of generated code
}
/**
* This class represents historical information about an app op.
*
* @hide
*/
@TestApi
@SystemApi
public static final class HistoricalOp implements Parcelable {
private final int mOp;
private @Nullable LongSparseLongArray mAccessCount;
private @Nullable LongSparseLongArray mRejectCount;
private @Nullable LongSparseLongArray mAccessDuration;
/** @hide */
public HistoricalOp(int op) {
mOp = op;
}
private HistoricalOp(@NonNull HistoricalOp other) {
mOp = other.mOp;
if (other.mAccessCount != null) {
mAccessCount = other.mAccessCount.clone();
}
if (other.mRejectCount != null) {
mRejectCount = other.mRejectCount.clone();
}
if (other.mAccessDuration != null) {
mAccessDuration = other.mAccessDuration.clone();
}
}
private HistoricalOp(@NonNull Parcel parcel) {
mOp = parcel.readInt();
mAccessCount = readLongSparseLongArrayFromParcel(parcel);
mRejectCount = readLongSparseLongArrayFromParcel(parcel);
mAccessDuration = readLongSparseLongArrayFromParcel(parcel);
}
private void filter(double scaleFactor) {
scale(mAccessCount, scaleFactor);
scale(mRejectCount, scaleFactor);
scale(mAccessDuration, scaleFactor);
}
private boolean isEmpty() {
return !hasData(mAccessCount)
&& !hasData(mRejectCount)
&& !hasData(mAccessDuration);
}
private boolean hasData(@NonNull LongSparseLongArray array) {
return (array != null && array.size() > 0);
}
private @Nullable HistoricalOp splice(double fractionToRemove) {
final HistoricalOp splice = new HistoricalOp(mOp);
splice(mAccessCount, splice::getOrCreateAccessCount, fractionToRemove);
splice(mRejectCount, splice::getOrCreateRejectCount, fractionToRemove);
splice(mAccessDuration, splice::getOrCreateAccessDuration, fractionToRemove);
return splice;
}
private static void splice(@Nullable LongSparseLongArray sourceContainer,
@NonNull Supplier<LongSparseLongArray> destContainerProvider,
double fractionToRemove) {
if (sourceContainer != null) {
final int size = sourceContainer.size();
for (int i = 0; i < size; i++) {
final long key = sourceContainer.keyAt(i);
final long value = sourceContainer.valueAt(i);
final long removedFraction = Math.round(value * fractionToRemove);
if (removedFraction > 0) {
destContainerProvider.get().put(key, removedFraction);
sourceContainer.put(key, value - removedFraction);
}
}
}
}
private void merge(@NonNull HistoricalOp other) {
merge(this::getOrCreateAccessCount, other.mAccessCount);
merge(this::getOrCreateRejectCount, other.mRejectCount);
merge(this::getOrCreateAccessDuration, other.mAccessDuration);
}
private void increaseAccessCount(@UidState int uidState, @OpFlags int flags,
long increment) {
increaseCount(getOrCreateAccessCount(), uidState, flags, increment);
}
private void increaseRejectCount(@UidState int uidState, @OpFlags int flags,
long increment) {
increaseCount(getOrCreateRejectCount(), uidState, flags, increment);
}
private void increaseAccessDuration(@UidState int uidState, @OpFlags int flags,
long increment) {
increaseCount(getOrCreateAccessDuration(), uidState, flags, increment);
}
private void increaseCount(@NonNull LongSparseLongArray counts,
@UidState int uidState, @OpFlags int flags, long increment) {
while (flags != 0) {
final int flag = 1 << Integer.numberOfTrailingZeros(flags);
flags &= ~flag;
final long key = makeKey(uidState, flag);
counts.put(key, counts.get(key) + increment);
}
}
/**
* Gets the op name.
*
* @return The op name.
*/
public @NonNull String getOpName() {
return sOpToString[mOp];
}
/** @hide */
public int getOpCode() {
return mOp;
}
/**
* Gets the number times the op was accessed (performed) in the foreground.
*
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
* {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
* for any flag.
* @return The times the op was accessed in the foreground.
*
* @see #getBackgroundAccessCount(int)
* @see #getAccessCount(int, int, int)
*/
public long getForegroundAccessCount(@OpFlags int flags) {
return sumForFlagsInStates(mAccessCount, MAX_PRIORITY_UID_STATE,
resolveFirstUnrestrictedUidState(mOp), flags);
}
/**
* Gets the number times the op was accessed (performed) in the background.
*
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
* {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
* for any flag.
* @return The times the op was accessed in the background.
*
* @see #getForegroundAccessCount(int)
* @see #getAccessCount(int, int, int)
*/
public long getBackgroundAccessCount(@OpFlags int flags) {
return sumForFlagsInStates(mAccessCount, resolveLastRestrictedUidState(mOp),
MIN_PRIORITY_UID_STATE, flags);
}
/**
* Gets the number times the op was accessed (performed) for a
* range of uid states.
*
* @param fromUidState The UID state from which to query. Could be one of
* {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
* {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
* {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
* @param toUidState The UID state to which to query.
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
* {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
* for any flag.
*
* @return The times the op was accessed for the given UID state.
*
* @see #getForegroundAccessCount(int)
* @see #getBackgroundAccessCount(int)
*/
public long getAccessCount(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
return sumForFlagsInStates(mAccessCount, fromUidState, toUidState, flags);
}
/**
* Gets the number times the op was rejected in the foreground.
*
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
* {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
* for any flag.
* @return The times the op was rejected in the foreground.
*
* @see #getBackgroundRejectCount(int)
* @see #getRejectCount(int, int, int)
*/
public long getForegroundRejectCount(@OpFlags int flags) {
return sumForFlagsInStates(mRejectCount, MAX_PRIORITY_UID_STATE,
resolveFirstUnrestrictedUidState(mOp), flags);
}
/**
* Gets the number times the op was rejected in the background.
*
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
* {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
* for any flag.
* @return The times the op was rejected in the background.
*
* @see #getForegroundRejectCount(int)
* @see #getRejectCount(int, int, int)
*/
public long getBackgroundRejectCount(@OpFlags int flags) {
return sumForFlagsInStates(mRejectCount, resolveLastRestrictedUidState(mOp),
MIN_PRIORITY_UID_STATE, flags);
}
/**
* Gets the number times the op was rejected for a given range of UID states.
*
* @param fromUidState The UID state from which to query. Could be one of
* {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
* {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
* {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
* @param toUidState The UID state to which to query.
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
* {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
* for any flag.
*
* @return The times the op was rejected for the given UID state.
*
* @see #getForegroundRejectCount(int)
* @see #getBackgroundRejectCount(int)
*/
public long getRejectCount(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
return sumForFlagsInStates(mRejectCount, fromUidState, toUidState, flags);
}
/**
* Gets the total duration the app op was accessed (performed) in the foreground.
* The duration is in wall time.
*
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
* {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
* for any flag.
* @return The total duration the app op was accessed in the foreground.
*
* @see #getBackgroundAccessDuration(int)
* @see #getAccessDuration(int, int, int)
*/
public long getForegroundAccessDuration(@OpFlags int flags) {
return sumForFlagsInStates(mAccessDuration, MAX_PRIORITY_UID_STATE,
resolveFirstUnrestrictedUidState(mOp), flags);
}
/**
* Gets the total duration the app op was accessed (performed) in the background.
* The duration is in wall time.
*
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
* {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
* for any flag.
* @return The total duration the app op was accessed in the background.
*
* @see #getForegroundAccessDuration(int)
* @see #getAccessDuration(int, int, int)
*/
public long getBackgroundAccessDuration(@OpFlags int flags) {
return sumForFlagsInStates(mAccessDuration, resolveLastRestrictedUidState(mOp),
MIN_PRIORITY_UID_STATE, flags);
}
/**
* Gets the total duration the app op was accessed (performed) for a given
* range of UID states. The duration is in wall time.
*
* @param fromUidState The UID state from which to query. Could be one of
* {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
* {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
* {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
* @param toUidState The UID state from which to query.
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
* {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
* {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
* for any flag.
*
* @return The total duration the app op was accessed for the given UID state.
*
* @see #getForegroundAccessDuration(int)
* @see #getBackgroundAccessDuration(int)
*/
public long getAccessDuration(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
return sumForFlagsInStates(mAccessDuration, fromUidState, toUidState, flags);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mOp);
writeLongSparseLongArrayToParcel(mAccessCount, parcel);
writeLongSparseLongArrayToParcel(mRejectCount, parcel);
writeLongSparseLongArrayToParcel(mAccessDuration, parcel);
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final HistoricalOp other = (HistoricalOp) obj;
if (mOp != other.mOp) {
return false;
}
if (!equalsLongSparseLongArray(mAccessCount, other.mAccessCount)) {
return false;
}
if (!equalsLongSparseLongArray(mRejectCount, other.mRejectCount)) {
return false;
}
return equalsLongSparseLongArray(mAccessDuration, other.mAccessDuration);
}
@Override
public int hashCode() {
int result = mOp;
result = 31 * result + Objects.hashCode(mAccessCount);
result = 31 * result + Objects.hashCode(mRejectCount);
result = 31 * result + Objects.hashCode(mAccessDuration);
return result;
}
private void accept(@NonNull HistoricalOpsVisitor visitor) {
visitor.visitHistoricalOp(this);
}
private @NonNull LongSparseLongArray getOrCreateAccessCount() {
if (mAccessCount == null) {
mAccessCount = new LongSparseLongArray();
}
return mAccessCount;
}
private @NonNull LongSparseLongArray getOrCreateRejectCount() {
if (mRejectCount == null) {
mRejectCount = new LongSparseLongArray();
}
return mRejectCount;
}
private @NonNull LongSparseLongArray getOrCreateAccessDuration() {
if (mAccessDuration == null) {
mAccessDuration = new LongSparseLongArray();
}
return mAccessDuration;
}
/**
* Multiplies the entries in the array with the passed in scale factor and
* rounds the result at up 0.5 boundary.
*
* @param data The data to scale.
* @param scaleFactor The scale factor.
*/
private static void scale(@NonNull LongSparseLongArray data, double scaleFactor) {
if (data != null) {
final int size = data.size();
for (int i = 0; i < size; i++) {
data.put(data.keyAt(i), (long) HistoricalOps.round(
(double) data.valueAt(i) * scaleFactor));
}
}
}
/**
* Merges two arrays while lazily acquiring the destination.
*
* @param thisSupplier The destination supplier.
* @param other The array to merge in.
*/
private static void merge(@NonNull Supplier<LongSparseLongArray> thisSupplier,
@Nullable LongSparseLongArray other) {
if (other != null) {
final int otherSize = other.size();
for (int i = 0; i < otherSize; i++) {
final LongSparseLongArray that = thisSupplier.get();
final long otherKey = other.keyAt(i);
final long otherValue = other.valueAt(i);
that.put(otherKey, that.get(otherKey) + otherValue);
}
}
}
/** @hide */
public @Nullable LongSparseArray<Object> collectKeys() {
LongSparseArray<Object> result = AppOpsManager.collectKeys(mAccessCount,
null /*result*/);
result = AppOpsManager.collectKeys(mRejectCount, result);
result = AppOpsManager.collectKeys(mAccessDuration, result);
return result;
}
public static final @android.annotation.NonNull Creator<HistoricalOp> CREATOR =
new Creator<HistoricalOp>() {
@Override
public @NonNull HistoricalOp createFromParcel(@NonNull Parcel source) {
return new HistoricalOp(source);
}
@Override
public @NonNull HistoricalOp[] newArray(int size) {
return new HistoricalOp[size];
}
};
}
/**
* Computes the sum of the counts for the given flags in between the begin and
* end UID states.
*
* @param counts The data array.
* @param beginUidState The beginning UID state (inclusive).
* @param endUidState The end UID state (inclusive).
* @param flags The UID flags.
* @return The sum.
*/
private static long sumForFlagsInStates(@Nullable LongSparseLongArray counts,
@UidState int beginUidState, @UidState int endUidState, @OpFlags int flags) {
if (counts == null) {
return 0;
}
long sum = 0;
while (flags != 0) {
final int flag = 1 << Integer.numberOfTrailingZeros(flags);
flags &= ~flag;
for (int uidState : UID_STATES) {
if (uidState < beginUidState || uidState > endUidState) {
continue;
}
final long key = makeKey(uidState, flag);
sum += counts.get(key);
}
}
return sum;
}
/**
* 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 active state.
*/
public interface OnOpActiveChangedListener {
/**
* Called when the active state of an app op changes.
*
* @param op The operation that changed.
* @param packageName The package performing the operation.
* @param active Whether the operation became active or inactive.
*/
void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName,
boolean active);
}
/**
* Callback for notification of an op being noted.
*
* @hide
*/
public interface OnOpNotedListener {
/**
* Called when an op was noted.
*
* @param code The op code.
* @param uid The UID performing the operation.
* @param packageName The package performing the operation.
* @param result The result of the note.
*/
void onOpNoted(int code, int uid, String packageName, int result);
}
/**
* 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) { }
}
/**
* Callback for notification of changes to operation state.
* This allows you to see the raw op codes instead of strings.
* @hide
*/
public interface OnOpActiveChangedInternalListener extends OnOpActiveChangedListener {
default void onOpActiveChanged(String op, int uid, String packageName, boolean active) { }
default void onOpActiveChanged(int op, int uid, String packageName, boolean active) { }
}
AppOpsManager(Context context, IAppOpsService service) {
mContext = context;
mService = service;
}
/**
* Retrieve current operation state for all applications.
*
* The mode of the ops returned are set for the package but may not reflect their effective
* state due to UID policy or because it's controlled by a different master op.
*
* Use {@link #unsafeCheckOp(String, int, String)}} or
* {@link #noteOp(String, int, String, String, String)} if the effective mode is needed.
*
* @param ops The set of operations you are interested in, or null if you want all of them.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
public @NonNull List<AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[] ops) {
final int opCount = ops.length;
final int[] opCodes = new int[opCount];
for (int i = 0; i < opCount; i++) {
opCodes[i] = sOpStrToOp.get(ops[i]);
}
final List<AppOpsManager.PackageOps> result = getPackagesForOps(opCodes);
return (result != null) ? result : Collections.emptyList();
}
/**
* Retrieve current operation state for all applications.
*
* The mode of the ops returned are set for the package but may not reflect their effective
* state due to UID policy or because it's controlled by a different master op.
*
* Use {@link #unsafeCheckOp(String, int, String)}} or
* {@link #noteOp(String, int, String, String, String)} if the effective mode is needed.
*
* @param ops The set of operations you are interested in, or null if you want all of them.
* @hide
*/
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
@UnsupportedAppUsage
public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
try {
return mService.getPackagesForOps(ops);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Retrieve current operation state for one application.
*
* The mode of the ops returned are set for the package but may not reflect their effective
* state due to UID policy or because it's controlled by a different master op.
*
* Use {@link #unsafeCheckOp(String, int, String)}} or
* {@link #noteOp(String, int, String, String, String)} if the effective mode is needed.
*
* @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.
*
* @deprecated The int op codes are not stable and you should use the string based op
* names which are stable and namespaced. Use
* {@link #getOpsForPackage(int, String, String...)})}.
*
* @hide
* @removed
*/
@Deprecated
@SystemApi
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
public @NonNull List<PackageOps> getOpsForPackage(int uid, @NonNull String packageName,
@Nullable int[] ops) {
try {
return mService.getOpsForPackage(uid, packageName, ops);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Retrieve current operation state for one application. The UID and the
* package must match.
*
* The mode of the ops returned are set for the package but may not reflect their effective
* state due to UID policy or because it's controlled by a different master op.
*
* Use {@link #unsafeCheckOp(String, int, String)}} or
* {@link #noteOp(String, int, String, String, String)} if the effective mode is needed.
*
* @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
*/
@TestApi
@SystemApi
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
public @NonNull List<AppOpsManager.PackageOps> getOpsForPackage(int uid,
@NonNull String packageName, @Nullable String... ops) {
int[] opCodes = null;
if (ops != null) {
opCodes = new int[ops.length];
for (int i = 0; i < ops.length; i++) {
opCodes[i] = strOpToOp(ops[i]);
}
}
try {
final List<PackageOps> result = mService.getOpsForPackage(uid, packageName, opCodes);
if (result == null) {
return Collections.emptyList();
}
return result;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Retrieve historical app op stats for a period.
*
* @param request A request object describing the data being queried for.
* @param executor Executor on which to run the callback. If <code>null</code>
* the callback is executed on the default executor running on the main thread.
* @param callback Callback on which to deliver the result.
*
* @throws IllegalArgumentException If any of the argument contracts is violated.
*
* @hide
*/
@TestApi
@SystemApi
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
public void getHistoricalOps(@NonNull HistoricalOpsRequest request,
@NonNull Executor executor, @NonNull Consumer<HistoricalOps> callback) {
Objects.requireNonNull(executor, "executor cannot be null");
Objects.requireNonNull(callback, "callback cannot be null");
try {
mService.getHistoricalOps(request.mUid, request.mPackageName, request.mFeatureId,
request.mOpNames, request.mFilter, request.mBeginTimeMillis,
request.mEndTimeMillis, request.mFlags, new RemoteCallback((result) -> {
final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
final long identity = Binder.clearCallingIdentity();
try {
executor.execute(() -> callback.accept(ops));
} finally {
Binder.restoreCallingIdentity(identity);
}
}));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Retrieve historical app op stats for a period.
* <p>
* This method queries only the on disk state and the returned ops are raw,
* which is their times are relative to the history start as opposed to the
* epoch start.
*
* @param request A request object describing the data being queried for.
* @param executor Executor on which to run the callback. If <code>null</code>
* the callback is executed on the default executor running on the main thread.
* @param callback Callback on which to deliver the result.
*
* @throws IllegalArgumentException If any of the argument contracts is violated.
*
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_APPOPS)
public void getHistoricalOpsFromDiskRaw(@NonNull HistoricalOpsRequest request,
@Nullable Executor executor, @NonNull Consumer<HistoricalOps> callback) {
Objects.requireNonNull(executor, "executor cannot be null");
Objects.requireNonNull(callback, "callback cannot be null");
try {
mService.getHistoricalOpsFromDiskRaw(request.mUid, request.mPackageName,
request.mFeatureId, request.mOpNames, request.mFilter, request.mBeginTimeMillis,
request.mEndTimeMillis, request.mFlags, new RemoteCallback((result) -> {
final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
final long identity = Binder.clearCallingIdentity();
try {
executor.execute(() -> callback.accept(ops));
} finally {
Binder.restoreCallingIdentity(identity);
}
}));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Reloads the non historical state to allow testing the read/write path.
*
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_APPOPS)
public void reloadNonHistoricalState() {
try {
mService.reloadNonHistoricalState();
} 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
*/
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setUidMode(int code, int uid, @Mode 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
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setUidMode(String appOp, int uid, @Mode 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 */
@UnsupportedAppUsage
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setMode(int code, int uid, String packageName, @Mode int mode) {
try {
mService.setMode(code, uid, packageName, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Change the operating mode for the given op in the given app package. You must pass
* in both the uid and name of the application whose mode is being modified; if these
* do not match, the modification will not be applied.
*
* @param op The operation to modify. One of the OPSTR_* constants.
* @param uid The user id of the application whose mode will be changed.
* @param packageName The name of the application package name whose mode will
* be changed.
* @hide
*/
@TestApi
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setMode(String op, int uid, String packageName, @Mode int mode) {
try {
mService.setMode(strOpToOp(op), 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
*/
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
@UnsupportedAppUsage
public void setRestriction(int code, @AttributeUsage int usage, @Mode int mode,
String[] exceptionPackages) {
try {
final int uid = Binder.getCallingUid();
mService.setAudioRestriction(code, usage, uid, mode, exceptionPackages);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** @hide */
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
@UnsupportedAppUsage
public void resetAllModes() {
try {
mService.resetAllModes(mContext.getUserId(), 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 = sPermToOp.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.
* You can watch op changes only for your UID.
*
* @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(@NonNull String op, @Nullable String packageName,
@NonNull final OnOpChangedListener callback) {
startWatchingMode(strOpToOp(op), packageName, callback);
}
/**
* Monitor for changes to the operating mode for the given op in the given app package.
* You can watch op changes only for your UID.
*
* @param op The operation to monitor, one of OPSTR_*.
* @param packageName The name of the application to monitor.
* @param flags Option flags: any combination of {@link #WATCH_FOREGROUND_CHANGES} or 0.
* @param callback Where to report changes.
*/
public void startWatchingMode(@NonNull String op, @Nullable String packageName, int flags,
@NonNull final OnOpChangedListener callback) {
startWatchingMode(strOpToOp(op), packageName, flags, callback);
}
/**
* Monitor for changes to the operating mode for the given op in the given app package.
*
* <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
* you can watch changes only for your UID.
*
* @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
*/
@RequiresPermission(value=android.Manifest.permission.WATCH_APPOPS, conditional=true)
public void startWatchingMode(int op, String packageName, final OnOpChangedListener callback) {
startWatchingMode(op, packageName, 0, callback);
}
/**
* Monitor for changes to the operating mode for the given op in the given app package.
*
* <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
* you can watch changes only for your UID.
*
* @param op The operation to monitor, one of OP_*.
* @param packageName The name of the application to monitor.
* @param flags Option flags: any combination of {@link #WATCH_FOREGROUND_CHANGES} or 0.
* @param callback Where to report changes.
* @hide
*/
@RequiresPermission(value=android.Manifest.permission.WATCH_APPOPS, conditional=true)
public void startWatchingMode(int op, String packageName, int flags,
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.startWatchingModeWithFlags(op, packageName, flags, 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(@NonNull OnOpChangedListener callback) {
synchronized (mModeWatchers) {
IAppOpsCallback cb = mModeWatchers.remove(callback);
if (cb != null) {
try {
mService.stopWatchingMode(cb);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
/** {@hide} */
@Deprecated
public void startWatchingActive(@NonNull int[] ops,
@NonNull OnOpActiveChangedListener callback) {
final String[] strOps = new String[ops.length];
for (int i = 0; i < ops.length; i++) {
strOps[i] = opToPublicName(ops[i]);
}
startWatchingActive(strOps, mContext.getMainExecutor(), callback);
}
/**
* Start watching for changes to the active state of app ops. An app op may be
* long running and it has a clear start and stop delimiters. If an op is being
* started or stopped by any package you will get a callback. To change the
* watched ops for a registered callback you need to unregister and register it
* again.
*
* <p> If you don't hold the {@code android.Manifest.permission#WATCH_APPOPS} permission
* you can watch changes only for your UID.
*
* @param ops The operations to watch.
* @param callback Where to report changes.
*
* @see #isOperationActive
* @see #stopWatchingActive
* @see #startOp(int, int, String, boolean, String, String)
* @see #finishOp(int, int, String, String)
*/
// TODO: Uncomment below annotation once b/73559440 is fixed
// @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true)
public void startWatchingActive(@NonNull String[] ops,
@CallbackExecutor @NonNull Executor executor,
@NonNull OnOpActiveChangedListener callback) {
Objects.requireNonNull(ops);
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
IAppOpsActiveCallback cb;
synchronized (mActiveWatchers) {
cb = mActiveWatchers.get(callback);
if (cb != null) {
return;
}
cb = new IAppOpsActiveCallback.Stub() {
@Override
public void opActiveChanged(int op, int uid, String packageName, boolean active) {
executor.execute(() -> {
if (callback instanceof OnOpActiveChangedInternalListener) {
((OnOpActiveChangedInternalListener) callback).onOpActiveChanged(op,
uid, packageName, active);
}
if (sOpToString[op] != null) {
callback.onOpActiveChanged(sOpToString[op], uid, packageName, active);
}
});
}
};
mActiveWatchers.put(callback, cb);
}
final int[] rawOps = new int[ops.length];
for (int i = 0; i < ops.length; i++) {
rawOps[i] = strOpToOp(ops[i]);
}
try {
mService.startWatchingActive(rawOps, cb);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Stop watching for changes to the active state of an app op. An app op may be
* long running and it has a clear start and stop delimiters. Unregistering a
* non-registered callback has no effect.
*
* @see #isOperationActive
* @see #startWatchingActive
* @see #startOp(int, int, String, boolean, String, String)
* @see #finishOp(int, int, String, String)
*/
public void stopWatchingActive(@NonNull OnOpActiveChangedListener callback) {
synchronized (mActiveWatchers) {
final IAppOpsActiveCallback cb = mActiveWatchers.remove(callback);
if (cb != null) {
try {
mService.stopWatchingActive(cb);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
/**
* Start watching for noted app ops. An app op may be immediate or long running.
* Immediate ops are noted while long running ones are started and stopped. This
* method allows registering a listener to be notified when an app op is noted. If
* an op is being noted by any package you will get a callback. To change the
* watched ops for a registered callback you need to unregister and register it again.
*
* <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
* you can watch changes only for your UID.
*
* @param ops The ops to watch.
* @param callback Where to report changes.
*
* @see #startWatchingActive(int[], OnOpActiveChangedListener)
* @see #stopWatchingNoted(OnOpNotedListener)
* @see #noteOp(String, int, String, String, String)
*
* @hide
*/
@RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true)
public void startWatchingNoted(@NonNull int[] ops, @NonNull OnOpNotedListener callback) {
IAppOpsNotedCallback cb;
synchronized (mNotedWatchers) {
cb = mNotedWatchers.get(callback);
if (cb != null) {
return;
}
cb = new IAppOpsNotedCallback.Stub() {
@Override
public void opNoted(int op, int uid, String packageName, int mode) {
callback.onOpNoted(op, uid, packageName, mode);
}
};
mNotedWatchers.put(callback, cb);
}
try {
mService.startWatchingNoted(ops, cb);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Stop watching for noted app ops. An app op may be immediate or long running.
* Unregistering a non-registered callback has no effect.
*
* @see #startWatchingNoted(int[], OnOpNotedListener)
* @see #noteOp(String, int, String, String, String)
*
* @hide
*/
public void stopWatchingNoted(@NonNull OnOpNotedListener callback) {
synchronized (mNotedWatchers) {
final IAppOpsNotedCallback cb = mNotedWatchers.get(callback);
if (cb != null) {
try {
mService.stopWatchingNoted(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}
*/
@UnsupportedAppUsage
@TestApi
public static int strOpToOp(@NonNull 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 <em>not</em> a security check; you must use {@link #noteOp(String, int, String,
* String, String)} or {@link #startOp(String, int, String, String, 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.
*
* <p>Important things this will not do (which you need to ultimate use
* {@link #noteOp(String, int, String, String, String)} or
* {@link #startOp(String, int, String, String, String)} to cover):</p>
* <ul>
* <li>Verifying the uid and package are consistent, so callers can't spoof
* their identity.</li>
* <li>Taking into account the current foreground/background state of the
* app; apps whose mode varies by this state will always be reported
* as {@link #MODE_ALLOWED}.</li>
* </ul>
*
* @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 unsafeCheckOp(@NonNull String op, int uid, @NonNull String packageName) {
return checkOp(strOpToOp(op), uid, packageName);
}
/**
* @deprecated Renamed to {@link #unsafeCheckOp(String, int, String)}.
*/
@Deprecated
public int checkOp(@NonNull String op, int uid, @NonNull 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 unsafeCheckOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
return checkOpNoThrow(strOpToOp(op), uid, packageName);
}
/**
* @deprecated Renamed to {@link #unsafeCheckOpNoThrow(String, int, String)}.
*/
@Deprecated
public int checkOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
return checkOpNoThrow(strOpToOp(op), uid, packageName);
}
/**
* Like {@link #checkOp} but returns the <em>raw</em> mode associated with the op.
* Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
*/
public int unsafeCheckOpRaw(@NonNull String op, int uid, @NonNull String packageName) {
try {
return mService.checkOperationRaw(strOpToOp(op), uid, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Like {@link #unsafeCheckOpNoThrow(String, int, String)} but returns the <em>raw</em>
* mode associated with the op. Does not throw a security exception, does not translate
* {@link #MODE_FOREGROUND}.
*/
public int unsafeCheckOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
try {
return mService.checkOperationRaw(strOpToOp(op), uid, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @deprecated Use {@link #noteOp(String, int, String, String, String)} instead
*/
@Deprecated
public int noteOp(@NonNull String op, int uid, @NonNull String packageName) {
return noteOp(op, uid, packageName, null, null);
}
/**
* @deprecated Use {@link #noteOp(String, int, String, String, String)} instead
*
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+ "#noteOp(java.lang.String, int, java.lang.String, java.lang.String, "
+ "java.lang.String)} instead")
@Deprecated
public int noteOp(int op) {
return noteOp(op, Process.myUid(), mContext.getOpPackageName(), null, null);
}
/**
* @deprecated Use {@link #noteOp(String, int, String, String, String)} instead
*
* @hide
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+ "#noteOp(java.lang.String, int, java.lang.String, java.lang.String, "
+ "java.lang.String)} instead")
public int noteOp(int op, int uid, @Nullable String packageName) {
return noteOp(op, uid, packageName, null, null);
}
/**
* 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.
* @param featureId The feature in the app or {@code null} for default feature
* @param message A message describing the reason the op was noted
*
* @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(@NonNull String op, int uid, @Nullable String packageName,
@Nullable String featureId, @Nullable String message) {
return noteOp(strOpToOp(op), uid, packageName, featureId, message);
}
/**
* 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.
* @param featureId The feature in the app or {@code null} for default feature
* @param message A message describing the reason the op was noted
*
* @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, @Nullable String packageName, @Nullable String featureId,
@Nullable String message) {
final int mode = noteOpNoThrow(op, uid, packageName, featureId, message);
if (mode == MODE_ERRORED) {
throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
return mode;
}
/**
* @deprecated Use {@link #noteOpNoThrow(String, int, String, String, String)} instead
*/
@Deprecated
public int noteOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
return noteOpNoThrow(op, uid, packageName, null, null);
}
/**
* @deprecated Use {@link #noteOpNoThrow(int, int, String, String, String)} instead
*
* @hide
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+ "#noteOpNoThrow(java.lang.String, int, java.lang.String, java.lang.String, "
+ "java.lang.String)} instead")
public int noteOpNoThrow(int op, int uid, String packageName) {
return noteOpNoThrow(op, uid, packageName, null, null);
}
/**
* Like {@link #noteOp(String, int, String, String, String)} but instead of throwing a
* {@link SecurityException} it returns {@link #MODE_ERRORED}.
*
* @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.
* @param message A message describing the reason the op was noted
*
* @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).
*/
public int noteOpNoThrow(@NonNull String op, int uid, @NonNull String packageName,
@Nullable String feature, @Nullable String message) {
return noteOpNoThrow(strOpToOp(op), uid, packageName, feature, message);
}
/**
* Like {@link #noteOp(String, int, String, String, String)} but instead of throwing a
* {@link SecurityException} it returns {@link #MODE_ERRORED}.
*
* @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.
* @param featureId The feature in the app or {@code null} for default feature
* @param message A message describing the reason the op was noted
*
* @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).
*
* @hide
*/
public int noteOpNoThrow(int op, int uid, @Nullable String packageName,
@Nullable String featureId, @Nullable String message) {
try {
int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
if (collectionMode == COLLECT_ASYNC) {
if (message == null) {
// Set stack trace as default message
message = getFormattedStackTrace();
}
}
int mode = mService.noteOperation(op, uid, packageName, featureId,
collectionMode == COLLECT_ASYNC, message);
if (mode == MODE_ALLOWED) {
if (collectionMode == COLLECT_SELF) {
collectNotedOpForSelf(op, featureId);
} else if (collectionMode == COLLECT_SYNC) {
collectNotedOpSync(op, featureId);
}
}
return mode;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @deprecated Use {@link #noteProxyOp(String, String, int, String, String)} instead
*/
@Deprecated
public int noteProxyOp(@NonNull String op, @NonNull String proxiedPackageName) {
return noteProxyOp(op, proxiedPackageName, Binder.getCallingUid(), null, null);
}
/**
* @deprecated Use {@link #noteProxyOp(String, String, int, String, String)} instead
*
* @hide
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+ "#noteProxyOp(java.lang.String, java.lang.String, int, java.lang.String, "
+ "java.lang.String)} instead")
public int noteProxyOp(int op, @Nullable String proxiedPackageName) {
return noteProxyOp(op, proxiedPackageName, Binder.getCallingUid(), null, null);
}
/**
* Make note of an application performing an operation on behalf of another application when
* handling an IPC. 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 OP_* constants.
* @param proxiedPackageName The name of the application calling into the proxy application.
* @param proxiedUid The uid of the proxied application
* @param proxiedFeatureId The feature in the proxied app or {@code null} for default
* feature
* @param message A message describing the reason the op was noted
*
* @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, @Nullable String proxiedPackageName, int proxiedUid,
@Nullable String proxiedFeatureId, @Nullable String message) {
int mode = noteProxyOpNoThrow(op, proxiedPackageName, proxiedUid, proxiedFeatureId,
message);
if (mode == MODE_ERRORED) {
throw new SecurityException("Proxy package " + mContext.getOpPackageName()
+ " from uid " + Process.myUid() + " or calling package " + proxiedPackageName
+ " from uid " + proxiedUid + " not allowed to perform " + sOpNames[op]);
}
return mode;
}
/**
* Make note of an application performing an operation on behalf of another application when
* handling an IPC. 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.
* @param proxiedUid The uid of the proxied application
* @param proxiedFeatureId The feature in the proxied app or {@code null} for default
* feature
* @param message A message describing the reason the op was noted
*
* @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.
*/
public int noteProxyOp(@NonNull String op, @Nullable String proxiedPackageName, int proxiedUid,
@Nullable String proxiedFeatureId, @Nullable String message) {
return noteProxyOp(strOpToOp(op), proxiedPackageName, proxiedUid, proxiedFeatureId,
message);
}
/**
* @deprecated Use {@link #noteProxyOpNoThrow(String, String, int, String, String)} instead
*/
@Deprecated
public int noteProxyOpNoThrow(@NonNull String op, @NonNull String proxiedPackageName) {
return noteProxyOpNoThrow(op, proxiedPackageName, Binder.getCallingUid(), null, null);
}
/**
* @deprecated Use {@link #noteProxyOpNoThrow(String, String, int, String, String)} instead
*/
@Deprecated
public int noteProxyOpNoThrow(@NonNull String op, @Nullable String proxiedPackageName,
int proxiedUid) {
return noteProxyOpNoThrow(op, proxiedPackageName, proxiedUid, null, null);
}
/**
* Like {@link #noteProxyOp(String, String, int, String, String)} but instead
* of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}.
*
* <p>This API requires package with the {@code proxiedPackageName} to belong to
* {@code proxiedUid}.
*
* @param op The op to note
* @param proxiedPackageName The package to note the op for
* @param proxiedUid The uid the package belongs to
* @param proxiedFeatureId The feature in the proxied app or {@code null} for default
* feature
* @param message A message describing the reason the op was noted
*/
public int noteProxyOpNoThrow(@NonNull String op, @Nullable String proxiedPackageName,
int proxiedUid, @Nullable String proxiedFeatureId, @Nullable String message) {
return noteProxyOpNoThrow(strOpToOp(op), proxiedPackageName, proxiedUid,
proxiedFeatureId, message);
}
/**
* Like {@link #noteProxyOp(int, String, int, String, String)} but instead
* of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}.
*
* @param op The op to note
* @param proxiedPackageName The package to note the op for or {@code null} if the op should be
* noted for the "android" package
* @param proxiedUid The uid the package belongs to
* @param proxiedFeatureId The feature in the proxied app or {@code null} for default
* feature
* @param message A message describing the reason the op was noted
*
* @hide
*/
public int noteProxyOpNoThrow(int op, @Nullable String proxiedPackageName, int proxiedUid,
@Nullable String proxiedFeatureId, @Nullable String message) {
int myUid = Process.myUid();
try {
int collectionMode = getNotedOpCollectionMode(proxiedUid, proxiedPackageName, op);
if (collectionMode == COLLECT_ASYNC) {
if (message == null) {
// Set stack trace as default message
message = getFormattedStackTrace();
}
}
int mode = mService.noteProxyOperation(op, proxiedUid, proxiedPackageName,
proxiedFeatureId, myUid, mContext.getOpPackageName(),
mContext.getFeatureId(), collectionMode == COLLECT_ASYNC, message);
if (mode == MODE_ALLOWED) {
if (collectionMode == COLLECT_SELF) {
collectNotedOpForSelf(op, proxiedFeatureId);
} else if (collectionMode == COLLECT_SYNC
// Only collect app-ops when the proxy is trusted
&& mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
myUid) == PackageManager.PERMISSION_GRANTED) {
collectNotedOpSync(op, proxiedFeatureId);
}
}
return mode;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Do a quick check for whether an application might be able to perform an operation.
* This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String,
* String, String)} or {@link #startOp(int, int, String, boolean, String, 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.
*
* <p>Important things this will not do (which you need to ultimate use
* {@link #noteOp(String, int, String, String, String)} or
* {@link #startOp(int, int, String, boolean, String, String)} to cover):</p>
* <ul>
* <li>Verifying the uid and package are consistent, so callers can't spoof
* their identity.</li>
* <li>Taking into account the current foreground/background state of the
* app; apps whose mode varies by this state will always be reported
* as {@link #MODE_ALLOWED}.</li>
* </ul>
*
* @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
*/
@UnsupportedAppUsage
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
*/
@UnsupportedAppUsage
public int checkOpNoThrow(int op, int uid, String packageName) {
try {
int mode = mService.checkOperation(op, uid, packageName);
return mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : mode;
} 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, @NonNull 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();
}
}
/**
* @deprecated Use own local {@link android.os.Binder#Binder()}
*
* @hide
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Create own "
+ "local {@link android.os.Binder}")
public static IBinder getToken(IAppOpsService service) {
return getClientId();
}
/** @hide */
public static IBinder getClientId() {
synchronized (AppOpsManager.class) {
if (sClientId == null) {
sClientId = new Binder();
}
return sClientId;
}
}
/**
* @deprecated use {@link #startOp(String, int, String, String, String)} instead
*/
@Deprecated
public int startOp(@NonNull String op, int uid, @NonNull String packageName) {
return startOp(op, uid, packageName, null, null);
}
/**
* @deprecated Use {@link #startOp(int, int, String, boolean, String, String)} instead
*
* @hide
*/
@Deprecated
public int startOp(int op) {
return startOp(op, Process.myUid(), mContext.getOpPackageName(), false, null, null);
}
/**
* @deprecated Use {@link #startOp(int, int, String, boolean, String, String)} instead
*
* @hide
*/
@Deprecated
public int startOp(int op, int uid, String packageName) {
return startOp(op, uid, packageName, false, null, null);
}
/**
* @deprecated Use {@link #startOp(int, int, String, boolean, String, String)} instead
*
* @hide
*/
@Deprecated
public int startOp(int op, int uid, String packageName, boolean startIfModeDefault) {
return startOp(op, uid, packageName, startIfModeDefault, null, null);
}
/**
* Report that an application has started executing a long-running 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.
* @param featureId The feature in the app or {@code null} for default feature
* @param message Description why op was started
*
* @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 or
* the package is not in the passed in UID.
*/
public int startOp(@NonNull String op, int uid, @Nullable String packageName,
@Nullable String featureId, @Nullable String message) {
return startOp(strOpToOp(op), uid, packageName, false, featureId, message);
}
/**
* Report that an application has started executing a long-running 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.
* @param featureId The feature in the app or {@code null} for default feature
* @param startIfModeDefault Whether to start if mode is {@link #MODE_DEFAULT}.
* @param message Description why op was started
*
* @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 or
* the package is not in the passed in UID.
*
* @hide
*/
public int startOp(int op, int uid, @Nullable String packageName, boolean startIfModeDefault,
@Nullable String featureId, @Nullable String message) {
final int mode = startOpNoThrow(op, uid, packageName, startIfModeDefault, featureId,
message);
if (mode == MODE_ERRORED) {
throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
return mode;
}
/**
* @deprecated use {@link #startOpNoThrow(String, int, String, String, String)} instead
*/
@Deprecated
public int startOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
return startOpNoThrow(op, uid, packageName, null, null);
}
/**
* @deprecated Use {@link #startOpNoThrow(int, int, String, boolean, String, String} instead
*
* @hide
*/
@Deprecated
public int startOpNoThrow(int op, int uid, String packageName) {
return startOpNoThrow(op, uid, packageName, false, null, null);
}
/**
* @deprecated Use {@link #startOpNoThrow(int, int, String, boolean, String, String} instead
*
* @hide
*/
@Deprecated
public int startOpNoThrow(int op, int uid, String packageName, boolean startIfModeDefault) {
return startOpNoThrow(op, uid, packageName, startIfModeDefault, null, null);
}
/**
* Like {@link #startOp(String, int, String, String, String)} but instead of throwing a
* {@link SecurityException} it returns {@link #MODE_ERRORED}.
*
* @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.
* @param featureId The feature in the app or {@code null} for default feature
* @param message Description why op was started
*
* @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).
*/
public int startOpNoThrow(@NonNull String op, int uid, @NonNull String packageName,
@NonNull String featureId, @Nullable String message) {
return startOpNoThrow(strOpToOp(op), uid, packageName, false, featureId, message);
}
/**
* Like {@link #startOp(int, int, String, boolean, String, String)} but instead of throwing a
* {@link SecurityException} it returns {@link #MODE_ERRORED}.
*
* @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.
* @param featureId The feature in the app or {@code null} for default feature
* @param startIfModeDefault Whether to start if mode is {@link #MODE_DEFAULT}.
* @param message Description why op was started
*
* @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).
*
* @hide
*/
public int startOpNoThrow(int op, int uid, @NonNull String packageName,
boolean startIfModeDefault, @Nullable String featureId, @Nullable String message) {
try {
int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
if (collectionMode == COLLECT_ASYNC) {
if (message == null) {
// Set stack trace as default message
message = getFormattedStackTrace();
}
}
int mode = mService.startOperation(getClientId(), op, uid, packageName,
featureId, startIfModeDefault, collectionMode == COLLECT_ASYNC, message);
if (mode == MODE_ALLOWED) {
if (collectionMode == COLLECT_SELF) {
collectNotedOpForSelf(op, featureId);
} else if (collectionMode == COLLECT_SYNC) {
collectNotedOpSync(op, featureId);
}
}
return mode;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* @deprecated Use {@link #finishOp(String, int, String, String)} instead
*
* @hide
*/
@Deprecated
public void finishOp(int op) {
finishOp(op, Process.myUid(), mContext.getOpPackageName(), null);
}
/**
* @deprecated Use {@link #finishOp(String, int, String, String)} instead
*/
public void finishOp(@NonNull String op, int uid, @NonNull String packageName) {
finishOp(strOpToOp(op), uid, packageName, null);
}
/**
* Report that an application is no longer performing an operation that had previously
* been started with {@link #startOp(String, int, String, String, 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(@NonNull String op, int uid, @NonNull String packageName,
@Nullable String featureId) {
finishOp(strOpToOp(op), uid, packageName, featureId);
}
/**
* @deprecated Use {@link #finishOp(int, int, String, String)} instead
*
* @hide
*/
public void finishOp(int op, int uid, @NonNull String packageName) {
finishOp(op, uid, packageName, null);
}
/**
* Report that an application is no longer performing an operation that had previously
* been started with {@link #startOp(int, int, String, boolean, String, 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, @NonNull String packageName,
@Nullable String featureId) {
try {
mService.finishOperation(getClientId(), op, uid, packageName, featureId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Checks whether the given op for a package is active.
* <p>
* If you don't hold the {@code android.Manifest.permission#WATCH_APPOPS}
* permission you can query only for your UID.
*
* @see #finishOp(String, int, String, String)
* @see #startOp(String, int, String, String, String)
*/
public boolean isOpActive(@NonNull String op, int uid, @NonNull String packageName) {
return isOperationActive(strOpToOp(op), uid, packageName);
}
/**
* Start collection of noted appops on this thread.
*
* <p>Called at the beginning of a two way binder transaction.
*
* @see #finishNotedAppOpsCollection()
*
* @hide
*/
public static void startNotedAppOpsCollection(int callingUid) {
sBinderThreadCallingUid.set(callingUid);
}
/**
* State of a temporarily paused noted app-ops collection.
*
* @see #pauseNotedAppOpsCollection()
*
* @hide
*/
public static class PausedNotedAppOpsCollection {
final int mUid;
final @Nullable ArrayMap<String, long[]> mCollectedNotedAppOps;
PausedNotedAppOpsCollection(int uid, @Nullable ArrayMap<String,
long[]> collectedNotedAppOps) {
mUid = uid;
mCollectedNotedAppOps = collectedNotedAppOps;
}
}
/**
* Temporarily suspend collection of noted app-ops when binder-thread calls into the other
* process. During such a call there might be call-backs coming back on the same thread which
* should not be accounted to the current collection.
*
* @return a state needed to resume the collection
*
* @hide
*/
public static @Nullable PausedNotedAppOpsCollection pauseNotedAppOpsCollection() {
Integer previousUid = sBinderThreadCallingUid.get();
if (previousUid != null) {
ArrayMap<String, long[]> previousCollectedNotedAppOps =
sAppOpsNotedInThisBinderTransaction.get();
sBinderThreadCallingUid.remove();
sAppOpsNotedInThisBinderTransaction.remove();
return new PausedNotedAppOpsCollection(previousUid, previousCollectedNotedAppOps);
}
return null;
}
/**
* Resume a collection paused via {@link #pauseNotedAppOpsCollection}.
*
* @param prevCollection The state of the previous collection
*
* @hide
*/
public static void resumeNotedAppOpsCollection(
@Nullable PausedNotedAppOpsCollection prevCollection) {
if (prevCollection != null) {
sBinderThreadCallingUid.set(prevCollection.mUid);
if (prevCollection.mCollectedNotedAppOps != null) {
sAppOpsNotedInThisBinderTransaction.set(prevCollection.mCollectedNotedAppOps);
}
}
}
/**
* Finish collection of noted appops on this thread.
*
* <p>Called at the end of a two way binder transaction.
*
* @see #startNotedAppOpsCollection(int)
*
* @hide
*/
public static void finishNotedAppOpsCollection() {
sBinderThreadCallingUid.remove();
sAppOpsNotedInThisBinderTransaction.remove();
}
/**
* Collect a noted op for the current process.
*
* @param op The noted op
* @param featureId The feature the op is noted for
*/
private void collectNotedOpForSelf(int op, @Nullable String featureId) {
synchronized (sLock) {
if (sNotedAppOpsCollector != null) {
sNotedAppOpsCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
}
}
}
/**
* Collect a noted op when inside of a two-way binder call.
*
* <p> Delivered to caller via {@link #prefixParcelWithAppOpsIfNeeded}
*
* @param op The noted op
* @param featureId The feature the op is noted for
*/
private void collectNotedOpSync(int op, @Nullable String featureId) {
// If this is inside of a two-way binder call:
// We are inside of a two-way binder call. Delivered to caller via
// {@link #prefixParcelWithAppOpsIfNeeded}
ArrayMap<String, long[]> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get();
if (appOpsNoted == null) {
appOpsNoted = new ArrayMap<>(1);
sAppOpsNotedInThisBinderTransaction.set(appOpsNoted);
}
long[] appOpsNotedForFeature = appOpsNoted.get(featureId);
if (appOpsNotedForFeature == null) {
appOpsNotedForFeature = new long[2];
appOpsNoted.put(featureId, appOpsNotedForFeature);
}
if (op < 64) {
appOpsNotedForFeature[0] |= 1L << op;
} else {
appOpsNotedForFeature[1] |= 1L << (op - 64);
}
}
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
DONT_COLLECT,
COLLECT_SELF,
COLLECT_SYNC,
COLLECT_ASYNC
})
private @interface NotedOpCollectionMode {}
private static final int DONT_COLLECT = 0;
private static final int COLLECT_SELF = 1;
private static final int COLLECT_SYNC = 2;
private static final int COLLECT_ASYNC = 3;
/**
* Mark an app-op as noted.
*/
private @NotedOpCollectionMode int getNotedOpCollectionMode(int uid,
@Nullable String packageName, int op) {
if (packageName == null) {
packageName = "android";
}
// check it the appops needs to be collected and cache result
if (sAppOpsToNote[op] == SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED) {
boolean shouldCollectNotes;
try {
shouldCollectNotes = mService.shouldCollectNotes(op);
} catch (RemoteException e) {
return DONT_COLLECT;
}
if (shouldCollectNotes) {
sAppOpsToNote[op] = SHOULD_COLLECT_NOTE_OP;
} else {
sAppOpsToNote[op] = SHOULD_NOT_COLLECT_NOTE_OP;
}
}
if (sAppOpsToNote[op] != SHOULD_COLLECT_NOTE_OP) {
return DONT_COLLECT;
}
synchronized (sLock) {
if (uid == Process.myUid()
&& packageName.equals(ActivityThread.currentOpPackageName())) {
return COLLECT_SELF;
}
}
Integer binderUid = sBinderThreadCallingUid.get();
if (binderUid != null && binderUid == uid) {
return COLLECT_SYNC;
} else {
return COLLECT_ASYNC;
}
}
/**
* Append app-ops noted in the current two-way binder transaction to parcel.
*
* <p>This is called on the callee side of a two way binder transaction just before the
* transaction returns.
*
* @param p the parcel to append the noted app-ops to
*
* @hide
*/
public static void prefixParcelWithAppOpsIfNeeded(@NonNull Parcel p) {
ArrayMap<String, long[]> notedAppOps = sAppOpsNotedInThisBinderTransaction.get();
if (notedAppOps == null) {
return;
}
p.writeInt(Parcel.EX_HAS_NOTED_APPOPS_REPLY_HEADER);
int numFeatureWithNotesAppOps = notedAppOps.size();
p.writeInt(numFeatureWithNotesAppOps);
for (int i = 0; i < numFeatureWithNotesAppOps; i++) {
p.writeString(notedAppOps.keyAt(i));
p.writeLong(notedAppOps.valueAt(i)[0]);
p.writeLong(notedAppOps.valueAt(i)[1]);
}
}
/**
* Read app-ops noted during a two-way binder transaction from parcel.
*
* <p>This is called on the calling side of a two way binder transaction just after the
* transaction returns.
*
* @param p The parcel to read from
*
* @hide
*/
public static void readAndLogNotedAppops(@NonNull Parcel p) {
int numFeaturesWithNotedAppOps = p.readInt();
for (int i = 0; i < numFeaturesWithNotedAppOps; i++) {
String featureId = p.readString();
long[] rawNotedAppOps = new long[2];
rawNotedAppOps[0] = p.readLong();
rawNotedAppOps[1] = p.readLong();
if (rawNotedAppOps[0] != 0 || rawNotedAppOps[1] != 0) {
BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps);
synchronized (sLock) {
for (int code = notedAppOps.nextSetBit(0); code != -1;
code = notedAppOps.nextSetBit(code + 1)) {
if (sNotedAppOpsCollector != null) {
sNotedAppOpsCollector.onNoted(new SyncNotedAppOp(code, featureId));
}
}
}
}
}
}
/**
* Register a new {@link AppOpsCollector}.
*
* <p>There can only ever be one collector per process. If there currently is a collector
* registered, it will be unregistered.
*
* <p><b>Only appops related to dangerous permissions are collected.</b>
*
* @param collector The collector to set or {@code null} to unregister.
*/
public void setNotedAppOpsCollector(@Nullable AppOpsCollector collector) {
synchronized (sLock) {
if (sNotedAppOpsCollector != null) {
try {
mService.stopWatchingAsyncNoted(mContext.getPackageName(),
sNotedAppOpsCollector.mAsyncCb);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
sNotedAppOpsCollector = collector;
if (sNotedAppOpsCollector != null) {
List<AsyncNotedAppOp> missedAsyncOps = null;
try {
mService.startWatchingAsyncNoted(mContext.getPackageName(),
sNotedAppOpsCollector.mAsyncCb);
missedAsyncOps = mService.extractAsyncOps(mContext.getPackageName());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
if (missedAsyncOps != null) {
int numMissedAsyncOps = missedAsyncOps.size();
for (int i = 0; i < numMissedAsyncOps; i++) {
final AsyncNotedAppOp asyncNotedAppOp = missedAsyncOps.get(i);
if (sNotedAppOpsCollector != null) {
sNotedAppOpsCollector.getAsyncNotedExecutor().execute(
() -> sNotedAppOpsCollector.onAsyncNoted(
asyncNotedAppOp));
}
}
}
}
}
}
/**
* @return {@code true} iff the process currently is currently collecting noted appops.
*
* @see #setNotedAppOpsCollector(AppOpsCollector)
*
* @hide
*/
public static boolean isCollectingNotedAppOps() {
synchronized (sLock) {
return sNotedAppOpsCollector != null;
}
}
/**
* Callback an app can choose to {@link #setNotedAppOpsCollector register} to monitor it's noted
* appops.
*
* <p><b>Only appops related to dangerous permissions are collected.</b>
*/
public abstract static class AppOpsCollector {
/** Callback registered with the system. This will receive the async notes ops */
private final IAppOpsAsyncNotedCallback mAsyncCb = new IAppOpsAsyncNotedCallback.Stub() {
@Override
public void opNoted(AsyncNotedAppOp op) {
Objects.requireNonNull(op);
getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
}
};
/**
* @return The executor for the system to use when calling {@link #onAsyncNoted}.
*/
public @NonNull Executor getAsyncNotedExecutor() {
return new HandlerExecutor(Handler.getMain());
}
/**
* Called when an app-op was noted for this package inside of a two-way binder-call.
*
* <p>Called on the calling thread just after executing the binder-call. This allows
* the app to e.g. collect stack traces to figure out where the access came from.
*
* @param op The op noted
*/
public abstract void onNoted(@NonNull SyncNotedAppOp op);
/**
* Called when this app noted an app-op for its own package.
*
* <p>Called on the thread the noted the op. This allows the app to e.g. collect stack
* traces to figure out where the access came from.
*
* @param op The op noted
*/
public abstract void onSelfNoted(@NonNull SyncNotedAppOp op);
/**
* Called when an app-op was noted for this package which cannot be delivered via the other
* two mechanisms.
*
* <p>Called as soon as possible after the app-op was noted, but the delivery delay is not
* guaranteed. Due to how async calls work in Android this might even be delivered slightly
* before the private data is delivered to the app.
*
* <p>If the app is not running or no {@link AppOpsCollector} is registered a small amount
* of noted app-ops are buffered and then delivered as soon as a collector is registered.
*
* @param asyncOp The op noted
*/
public abstract void onAsyncNoted(@NonNull AsyncNotedAppOp asyncOp);
}
/**
* Generate a stack trace used for noted app-ops logging.
*
* <p>This strips away the first few and last few stack trace elements as they are not
* interesting to apps.
*/
private static String getFormattedStackTrace() {
StackTraceElement[] trace = new Exception().getStackTrace();
int firstInteresting = 0;
for (int i = 0; i < trace.length; i++) {
if (trace[i].getClassName().startsWith(AppOpsManager.class.getName())
|| trace[i].getClassName().startsWith(Parcel.class.getName())
|| trace[i].getClassName().contains("$Stub$Proxy")
|| trace[i].getClassName().startsWith(DatabaseUtils.class.getName())
|| trace[i].getClassName().startsWith("android.content.ContentProviderProxy")
|| trace[i].getClassName().startsWith(ContentResolver.class.getName())) {
firstInteresting = i;
} else {
break;
}
}
int lastInteresting = trace.length - 1;
for (int i = trace.length - 1; i >= 0; i--) {
if (trace[i].getClassName().startsWith(HandlerThread.class.getName())
|| trace[i].getClassName().startsWith(Handler.class.getName())
|| trace[i].getClassName().startsWith(Looper.class.getName())
|| trace[i].getClassName().startsWith(Binder.class.getName())
|| trace[i].getClassName().startsWith(RuntimeInit.class.getName())
|| trace[i].getClassName().startsWith(ZygoteInit.class.getName())
|| trace[i].getClassName().startsWith(ActivityThread.class.getName())
|| trace[i].getClassName().startsWith(Method.class.getName())
|| trace[i].getClassName().startsWith("com.android.server.SystemServer")) {
lastInteresting = i;
} else {
break;
}
}
StringBuilder sb = new StringBuilder();
for (int i = firstInteresting; i <= lastInteresting; i++) {
sb.append(trace[i]);
if (i != lastInteresting) {
sb.append('\n');
}
}
return sb.toString();
}
/**
* Checks whether the given op for a UID and package is active.
*
* <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
* you can query only for your UID.
*
* @see #startWatchingActive(int[], OnOpActiveChangedListener)
* @see #stopWatchingMode(OnOpChangedListener)
* @see #finishOp(int, int, String, String)
* @see #startOp(int, int, String, boolean, String, String)
*
* @hide */
@TestApi
// TODO: Uncomment below annotation once b/73559440 is fixed
// @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true)
public boolean isOperationActive(int code, int uid, String packageName) {
try {
return mService.isOperationActive(code, uid, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Configures the app ops persistence for testing.
*
* @param mode The mode in which the historical registry operates.
* @param baseSnapshotInterval The base interval on which we would be persisting a snapshot of
* the historical data. The history is recursive where every subsequent step encompasses
* {@code compressionStep} longer interval with {@code compressionStep} distance between
* snapshots.
* @param compressionStep The compression step in every iteration.
*
* @see #HISTORICAL_MODE_DISABLED
* @see #HISTORICAL_MODE_ENABLED_ACTIVE
* @see #HISTORICAL_MODE_ENABLED_PASSIVE
*
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_APPOPS)
public void setHistoryParameters(@HistoricalMode int mode, long baseSnapshotInterval,
int compressionStep) {
try {
mService.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Offsets the history by the given duration.
*
* @param offsetMillis The offset duration.
*
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_APPOPS)
public void offsetHistory(long offsetMillis) {
try {
mService.offsetHistory(offsetMillis);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Adds ops to the history directly. This could be useful for testing especially
* when the historical registry operates in {@link #HISTORICAL_MODE_ENABLED_PASSIVE}
* mode.
*
* @param ops The ops to add to the history.
*
* @see #setHistoryParameters(int, long, int)
* @see #HISTORICAL_MODE_ENABLED_PASSIVE
*
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_APPOPS)
public void addHistoricalOps(@NonNull HistoricalOps ops) {
try {
mService.addHistoricalOps(ops);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Resets the app ops persistence for testing.
*
* @see #setHistoryParameters(int, long, int)
*
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_APPOPS)
public void resetHistoryParameters() {
try {
mService.resetHistoryParameters();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Clears all app ops history.
*
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_APPOPS)
public void clearHistory() {
try {
mService.clearHistory();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Returns all supported operation names.
* @hide
*/
@SystemApi
@TestApi
public static String[] getOpStrs() {
return Arrays.copyOf(sOpToString, sOpToString.length);
}
/**
* @return number of App ops
* @hide
*/
@TestApi
public static int getNumOps() {
return _NUM_OP;
}
/**
* Gets the last of the event.
*
* @param events The events
* @param flags The UID flags
* @param beginUidState The maximum UID state (inclusive)
* @param endUidState The minimum UID state (inclusive)
*
* @return The last event of {@code null}
*/
private static @Nullable NoteOpEvent getLastEvent(
@Nullable LongSparseArray<NoteOpEvent> events, @UidState int beginUidState,
@UidState int endUidState, @OpFlags int flags) {
if (events == null) {
return null;
}
NoteOpEvent lastEvent = null;
while (flags != 0) {
final int flag = 1 << Integer.numberOfTrailingZeros(flags);
flags &= ~flag;
for (int uidState : UID_STATES) {
if (uidState < beginUidState || uidState > endUidState) {
continue;
}
final long key = makeKey(uidState, flag);
NoteOpEvent event = events.get(key);
if (lastEvent == null
|| event != null && event.getNoteTime() > lastEvent.getNoteTime()) {
lastEvent = event;
}
}
}
return lastEvent;
}
private static boolean equalsLongSparseLongArray(@Nullable LongSparseLongArray a,
@Nullable LongSparseLongArray b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.size() != b.size()) {
return false;
}
int numEntries = a.size();
for (int i = 0; i < numEntries; i++) {
if (a.keyAt(i) != b.keyAt(i) || a.valueAt(i) != b.valueAt(i)) {
return false;
}
}
return true;
}
private static void writeLongSparseLongArrayToParcel(
@Nullable LongSparseLongArray array, @NonNull Parcel parcel) {
if (array != null) {
final int size = array.size();
parcel.writeInt(size);
for (int i = 0; i < size; i++) {
parcel.writeLong(array.keyAt(i));
parcel.writeLong(array.valueAt(i));
}
} else {
parcel.writeInt(-1);
}
}
private static @Nullable LongSparseLongArray readLongSparseLongArrayFromParcel(
@NonNull Parcel parcel) {
final int size = parcel.readInt();
if (size < 0) {
return null;
}
final LongSparseLongArray array = new LongSparseLongArray(size);
for (int i = 0; i < size; i++) {
array.append(parcel.readLong(), parcel.readLong());
}
return array;
}
/**
* Collects the keys from an array to the result creating the result if needed.
*
* @param array The array whose keys to collect.
* @param result The optional result store collected keys.
* @return The result collected keys array.
*/
private static LongSparseArray<Object> collectKeys(@Nullable LongSparseLongArray array,
@Nullable LongSparseArray<Object> result) {
if (array != null) {
if (result == null) {
result = new LongSparseArray<>();
}
final int accessSize = array.size();
for (int i = 0; i < accessSize; i++) {
result.put(array.keyAt(i), null);
}
}
return result;
}
/** @hide */
public static String uidStateToString(@UidState int uidState) {
switch (uidState) {
case UID_STATE_PERSISTENT: {
return "UID_STATE_PERSISTENT";
}
case UID_STATE_TOP: {
return "UID_STATE_TOP";
}
case UID_STATE_FOREGROUND_SERVICE_LOCATION: {
return "UID_STATE_FOREGROUND_SERVICE_LOCATION";
}
case UID_STATE_FOREGROUND_SERVICE: {
return "UID_STATE_FOREGROUND_SERVICE";
}
case UID_STATE_FOREGROUND: {
return "UID_STATE_FOREGROUND";
}
case UID_STATE_BACKGROUND: {
return "UID_STATE_BACKGROUND";
}
case UID_STATE_CACHED: {
return "UID_STATE_CACHED";
}
default: {
return "UNKNOWN";
}
}
}
/** @hide */
public static int parseHistoricalMode(@NonNull String mode) {
switch (mode) {
case "HISTORICAL_MODE_ENABLED_ACTIVE": {
return HISTORICAL_MODE_ENABLED_ACTIVE;
}
case "HISTORICAL_MODE_ENABLED_PASSIVE": {
return HISTORICAL_MODE_ENABLED_PASSIVE;
}
default: {
return HISTORICAL_MODE_DISABLED;
}
}
}
/** @hide */
public static String historicalModeToString(@HistoricalMode int mode) {
switch (mode) {
case HISTORICAL_MODE_DISABLED: {
return "HISTORICAL_MODE_DISABLED";
}
case HISTORICAL_MODE_ENABLED_ACTIVE: {
return "HISTORICAL_MODE_ENABLED_ACTIVE";
}
case HISTORICAL_MODE_ENABLED_PASSIVE: {
return "HISTORICAL_MODE_ENABLED_PASSIVE";
}
default: {
return "UNKNOWN";
}
}
}
private static int getSystemAlertWindowDefault() {
final Context context = ActivityThread.currentApplication();
if (context == null) {
return AppOpsManager.MODE_DEFAULT;
}
// system alert window is disable on low ram phones starting from Q
final PackageManager pm = context.getPackageManager();
// TVs are constantly plugged in and has less concern for memory/power
if (ActivityManager.isLowRamDeviceStatic()
&& !pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK, 0)) {
return AppOpsManager.MODE_IGNORED;
}
return AppOpsManager.MODE_DEFAULT;
}
}