Merge "Allow to exempt apps from restrictions to RECORD_AUDIO" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
093ba7e506
@@ -79,6 +79,7 @@ package android {
|
||||
field public static final String DEVICE_POWER = "android.permission.DEVICE_POWER";
|
||||
field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
|
||||
field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
|
||||
field public static final String EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS = "android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS";
|
||||
field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
|
||||
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
|
||||
field public static final String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
|
||||
|
||||
@@ -1988,108 +1988,108 @@ public class AppOpsManager {
|
||||
};
|
||||
|
||||
/**
|
||||
* This specifies whether each option should allow the system
|
||||
* (and system ui) to bypass the user restriction when active.
|
||||
* In which cases should an app be allowed to bypass the {@link #setUserRestriction user
|
||||
* restriction} for a certain app-op.
|
||||
*/
|
||||
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
|
||||
false, // LOADER_USAGE_STATS
|
||||
false, // ACCESS_CALL_AUDIO
|
||||
false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
|
||||
private static RestrictionBypass[] sOpAllowSystemRestrictionBypass = new RestrictionBypass[] {
|
||||
new RestrictionBypass(true, false), //COARSE_LOCATION
|
||||
new RestrictionBypass(true, false), //FINE_LOCATION
|
||||
null, //GPS
|
||||
null, //VIBRATE
|
||||
null, //READ_CONTACTS
|
||||
null, //WRITE_CONTACTS
|
||||
null, //READ_CALL_LOG
|
||||
null, //WRITE_CALL_LOG
|
||||
null, //READ_CALENDAR
|
||||
null, //WRITE_CALENDAR
|
||||
new RestrictionBypass(true, false), //WIFI_SCAN
|
||||
null, //POST_NOTIFICATION
|
||||
null, //NEIGHBORING_CELLS
|
||||
null, //CALL_PHONE
|
||||
null, //READ_SMS
|
||||
null, //WRITE_SMS
|
||||
null, //RECEIVE_SMS
|
||||
null, //RECEIVE_EMERGECY_SMS
|
||||
null, //RECEIVE_MMS
|
||||
null, //RECEIVE_WAP_PUSH
|
||||
null, //SEND_SMS
|
||||
null, //READ_ICC_SMS
|
||||
null, //WRITE_ICC_SMS
|
||||
null, //WRITE_SETTINGS
|
||||
new RestrictionBypass(true, false), //SYSTEM_ALERT_WINDOW
|
||||
null, //ACCESS_NOTIFICATIONS
|
||||
null, //CAMERA
|
||||
new RestrictionBypass(false, true), //RECORD_AUDIO
|
||||
null, //PLAY_AUDIO
|
||||
null, //READ_CLIPBOARD
|
||||
null, //WRITE_CLIPBOARD
|
||||
null, //TAKE_MEDIA_BUTTONS
|
||||
null, //TAKE_AUDIO_FOCUS
|
||||
null, //AUDIO_MASTER_VOLUME
|
||||
null, //AUDIO_VOICE_VOLUME
|
||||
null, //AUDIO_RING_VOLUME
|
||||
null, //AUDIO_MEDIA_VOLUME
|
||||
null, //AUDIO_ALARM_VOLUME
|
||||
null, //AUDIO_NOTIFICATION_VOLUME
|
||||
null, //AUDIO_BLUETOOTH_VOLUME
|
||||
null, //WAKE_LOCK
|
||||
null, //MONITOR_LOCATION
|
||||
null, //MONITOR_HIGH_POWER_LOCATION
|
||||
null, //GET_USAGE_STATS
|
||||
null, //MUTE_MICROPHONE
|
||||
new RestrictionBypass(true, false), //TOAST_WINDOW
|
||||
null, //PROJECT_MEDIA
|
||||
null, //ACTIVATE_VPN
|
||||
null, //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
|
||||
null, // 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, // OP_REQUEST_DELETE_PACKAGES
|
||||
null, // OP_BIND_ACCESSIBILITY_SERVICE
|
||||
null, // ACCEPT_HANDOVER
|
||||
null, // MANAGE_IPSEC_HANDOVERS
|
||||
null, // START_FOREGROUND
|
||||
new RestrictionBypass(true, false), // BLUETOOTH_SCAN
|
||||
null, // USE_BIOMETRIC
|
||||
null, // ACTIVITY_RECOGNITION
|
||||
null, // 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
|
||||
null, // LOADER_USAGE_STATS
|
||||
null, // ACCESS_CALL_AUDIO
|
||||
null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2485,11 +2485,11 @@ public class AppOpsManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve whether the op allows the system (and system ui) to
|
||||
* bypass the user restriction.
|
||||
* Retrieve whether the op allows to bypass the user restriction.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static boolean opAllowSystemBypassRestriction(int op) {
|
||||
public static RestrictionBypass opAllowSystemBypassRestriction(int op) {
|
||||
return sOpAllowSystemRestrictionBypass[op];
|
||||
}
|
||||
|
||||
@@ -2535,6 +2535,29 @@ public class AppOpsManager {
|
||||
return !sOpDisableReset[op];
|
||||
}
|
||||
|
||||
/**
|
||||
* When to not enforce {@link #setUserRestriction restrictions}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static class RestrictionBypass {
|
||||
/** Does the app need to be privileged to bypass the restriction */
|
||||
public boolean isPrivileged;
|
||||
|
||||
/**
|
||||
* Does the app need to have the EXEMPT_FROM_AUDIO_RESTRICTIONS permission to bypass the
|
||||
* restriction
|
||||
*/
|
||||
public boolean isRecordAudioRestrictionExcept;
|
||||
|
||||
public RestrictionBypass(boolean isPrivileged, boolean isRecordAudioRestrictionExcept) {
|
||||
this.isPrivileged = isPrivileged;
|
||||
this.isRecordAudioRestrictionExcept = isRecordAudioRestrictionExcept;
|
||||
}
|
||||
|
||||
public static RestrictionBypass UNRESTRICTED = new RestrictionBypass(true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class holding all of the operation information associated with an app.
|
||||
* @hide
|
||||
|
||||
@@ -1187,6 +1187,16 @@
|
||||
android:description="@string/permdesc_callCompanionApp"
|
||||
android:protectionLevel="normal" />
|
||||
|
||||
<!-- Exempt this uid from restrictions to background audio recoding
|
||||
<p>Protection level: signature|privileged
|
||||
@hide
|
||||
@SystemApi
|
||||
-->
|
||||
<permission android:name="android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS"
|
||||
android:label="@string/permlab_exemptFromAudioRecordRestrictions"
|
||||
android:description="@string/permdesc_exemptFromAudioRecordRestrictions"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- Allows a calling app to continue a call which was started in another app. An example is a
|
||||
video calling app that wants to continue a voice call on the user's mobile network.<p>
|
||||
When the handover of a call from one app to another takes place, there are two devices
|
||||
|
||||
@@ -1217,6 +1217,14 @@
|
||||
device. This includes information such as call numbers for calls and the state of the
|
||||
calls.</string>
|
||||
|
||||
<!-- Title of an application permission. When granted the app is exempt from audio record
|
||||
restrictions.
|
||||
[CHAR LIMIT=NONE]-->
|
||||
<string name="permlab_exemptFromAudioRecordRestrictions">exempt from audio record restrictions</string>
|
||||
<!-- Description of an application permission. When granted the app is exempt from audio record
|
||||
restrictions. [CHAR LIMIT=NONE]-->
|
||||
<string name="permdesc_exemptFromAudioRecordRestrictions">Exempt the app from restrictions to record audio.</string>
|
||||
|
||||
<!-- Title of an application permission. When granted the user is giving access to a third
|
||||
party app to continue a call which originated in another app. For example, the user
|
||||
could be in a voice call over their carrier's mobile network, and a third party video
|
||||
|
||||
@@ -40,6 +40,7 @@ import static android.app.AppOpsManager.OP_NONE;
|
||||
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
|
||||
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
|
||||
import static android.app.AppOpsManager.OpEventProxyInfo;
|
||||
import static android.app.AppOpsManager.RestrictionBypass;
|
||||
import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED;
|
||||
import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
|
||||
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
|
||||
@@ -55,6 +56,7 @@ import static android.app.AppOpsManager.extractFlagsFromKey;
|
||||
import static android.app.AppOpsManager.extractUidStateFromKey;
|
||||
import static android.app.AppOpsManager.makeKey;
|
||||
import static android.app.AppOpsManager.modeToName;
|
||||
import static android.app.AppOpsManager.opAllowSystemBypassRestriction;
|
||||
import static android.app.AppOpsManager.opToName;
|
||||
import static android.app.AppOpsManager.opToPublicName;
|
||||
import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
|
||||
@@ -73,7 +75,6 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.AppOpsManager.HistoricalOps;
|
||||
@@ -92,8 +93,6 @@ import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
@@ -666,15 +665,19 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
final static class Ops extends SparseArray<Op> {
|
||||
final String packageName;
|
||||
final UidState uidState;
|
||||
final boolean isPrivileged;
|
||||
|
||||
/**
|
||||
* The restriction properties of the package. If {@code null} it could not have been read
|
||||
* yet and has to be refreshed.
|
||||
*/
|
||||
@Nullable RestrictionBypass bypass;
|
||||
|
||||
/** Lazily populated cache of featureIds of this package */
|
||||
final @NonNull ArraySet<String> knownFeatureIds = new ArraySet<>();
|
||||
|
||||
Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
|
||||
Ops(String _packageName, UidState _uidState) {
|
||||
packageName = _packageName;
|
||||
uidState = _uidState;
|
||||
isPrivileged = _isPrivileged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1519,7 +1522,11 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset cached package properties to re-initialize when needed
|
||||
ops.bypass = null;
|
||||
ops.knownFeatureIds.clear();
|
||||
|
||||
// Merge data collected for removed features into their successor features
|
||||
int numOps = ops.size();
|
||||
for (int opNum = 0; opNum < numOps; opNum++) {
|
||||
Op op = ops.valueAt(opNum);
|
||||
@@ -1953,8 +1960,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
synchronized (this) {
|
||||
Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false /* isPrivileged */,
|
||||
false /* edit */);
|
||||
Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false /* edit */);
|
||||
if (pkgOps == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -2087,8 +2093,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
op.removeFeaturesWithNoTime();
|
||||
|
||||
if (op.mFeatures.size() == 0) {
|
||||
Ops ops = getOpsRawLocked(uid, packageName, null, false /* isPrivileged */,
|
||||
false /* edit */);
|
||||
Ops ops = getOpsLocked(uid, packageName, null, null, false /* edit */);
|
||||
if (ops != null) {
|
||||
ops.remove(op.op);
|
||||
if (ops.size() <= 0) {
|
||||
@@ -2390,9 +2395,9 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
ArraySet<ModeCallback> repCbs = null;
|
||||
code = AppOpsManager.opToSwitch(code);
|
||||
|
||||
boolean isPrivileged;
|
||||
RestrictionBypass bypass;
|
||||
try {
|
||||
isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
|
||||
bypass = verifyAndGetBypass(uid, packageName, null);
|
||||
} catch (SecurityException e) {
|
||||
Slog.e(TAG, "Cannot setMode", e);
|
||||
return;
|
||||
@@ -2400,7 +2405,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
|
||||
synchronized (this) {
|
||||
UidState uidState = getUidStateLocked(uid, false);
|
||||
Op op = getOpLocked(code, uid, packageName, null, isPrivileged, true);
|
||||
Op op = getOpLocked(code, uid, packageName, null, bypass, true);
|
||||
if (op != null) {
|
||||
if (op.mode != mode) {
|
||||
op.mode = mode;
|
||||
@@ -2798,10 +2803,9 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
*/
|
||||
private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
|
||||
boolean raw) {
|
||||
boolean isPrivileged;
|
||||
|
||||
RestrictionBypass bypass;
|
||||
try {
|
||||
isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
|
||||
bypass = verifyAndGetBypass(uid, packageName, null);
|
||||
} catch (SecurityException e) {
|
||||
Slog.e(TAG, "checkOperation", e);
|
||||
return AppOpsManager.opToDefaultMode(code);
|
||||
@@ -2811,7 +2815,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
return AppOpsManager.MODE_IGNORED;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (isOpRestrictedLocked(uid, code, packageName, null, isPrivileged)) {
|
||||
if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
|
||||
return AppOpsManager.MODE_IGNORED;
|
||||
}
|
||||
code = AppOpsManager.opToSwitch(code);
|
||||
@@ -2821,7 +2825,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
final int rawMode = uidState.opModes.get(code);
|
||||
return raw ? rawMode : uidState.evalMode(code, rawMode);
|
||||
}
|
||||
Op op = getOpLocked(code, uid, packageName, null, false, false);
|
||||
Op op = getOpLocked(code, uid, packageName, null, bypass, false);
|
||||
if (op == null) {
|
||||
return AppOpsManager.opToDefaultMode(code);
|
||||
}
|
||||
@@ -2884,7 +2888,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
public int checkPackage(int uid, String packageName) {
|
||||
Objects.requireNonNull(packageName);
|
||||
try {
|
||||
verifyAndGetIsPrivileged(uid, packageName, null);
|
||||
verifyAndGetBypass(uid, packageName, null);
|
||||
|
||||
return AppOpsManager.MODE_ALLOWED;
|
||||
} catch (SecurityException ignored) {
|
||||
@@ -2961,17 +2965,16 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
@Nullable String featureId, int proxyUid, String proxyPackageName,
|
||||
@Nullable String proxyFeatureId, @OpFlags int flags, boolean shouldCollectAsyncNotedOp,
|
||||
@Nullable String message) {
|
||||
boolean isPrivileged;
|
||||
RestrictionBypass bypass;
|
||||
try {
|
||||
isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
|
||||
bypass = verifyAndGetBypass(uid, packageName, featureId);
|
||||
} catch (SecurityException e) {
|
||||
Slog.e(TAG, "noteOperation", e);
|
||||
return AppOpsManager.MODE_ERRORED;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
final Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
|
||||
true /* edit */);
|
||||
final Ops ops = getOpsLocked(uid, packageName, featureId, bypass, true /* edit */);
|
||||
if (ops == null) {
|
||||
scheduleOpNotedIfNeededLocked(code, uid, packageName,
|
||||
AppOpsManager.MODE_IGNORED);
|
||||
@@ -2981,7 +2984,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
final Op op = getOpLocked(ops, code, uid, true);
|
||||
final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
|
||||
if (isOpRestrictedLocked(uid, code, packageName, featureId, isPrivileged)) {
|
||||
if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
|
||||
scheduleOpNotedIfNeededLocked(code, uid, packageName,
|
||||
AppOpsManager.MODE_IGNORED);
|
||||
return AppOpsManager.MODE_IGNORED;
|
||||
@@ -3205,7 +3208,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
int uid = Binder.getCallingUid();
|
||||
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
|
||||
|
||||
verifyAndGetIsPrivileged(uid, packageName, null);
|
||||
verifyAndGetBypass(uid, packageName, null);
|
||||
|
||||
synchronized (this) {
|
||||
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
|
||||
@@ -3235,7 +3238,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
int uid = Binder.getCallingUid();
|
||||
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
|
||||
|
||||
verifyAndGetIsPrivileged(uid, packageName, null);
|
||||
verifyAndGetBypass(uid, packageName, null);
|
||||
|
||||
synchronized (this) {
|
||||
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
|
||||
@@ -3254,7 +3257,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
|
||||
int uid = Binder.getCallingUid();
|
||||
|
||||
verifyAndGetIsPrivileged(uid, packageName, null);
|
||||
verifyAndGetBypass(uid, packageName, null);
|
||||
|
||||
synchronized (this) {
|
||||
return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
|
||||
@@ -3272,16 +3275,16 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
return AppOpsManager.MODE_IGNORED;
|
||||
}
|
||||
|
||||
boolean isPrivileged;
|
||||
RestrictionBypass bypass;
|
||||
try {
|
||||
isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
|
||||
bypass = verifyAndGetBypass(uid, packageName, featureId);
|
||||
} catch (SecurityException e) {
|
||||
Slog.e(TAG, "startOperation", e);
|
||||
return AppOpsManager.MODE_ERRORED;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
final Ops ops = getOpsRawLocked(uid, resolvedPackageName, featureId, isPrivileged,
|
||||
final Ops ops = getOpsLocked(uid, resolvedPackageName, featureId, bypass,
|
||||
true /* edit */);
|
||||
if (ops == null) {
|
||||
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
|
||||
@@ -3289,7 +3292,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
return AppOpsManager.MODE_ERRORED;
|
||||
}
|
||||
final Op op = getOpLocked(ops, code, uid, true);
|
||||
if (isOpRestrictedLocked(uid, code, resolvedPackageName, featureId, isPrivileged)) {
|
||||
if (isOpRestrictedLocked(uid, code, resolvedPackageName, bypass)) {
|
||||
return AppOpsManager.MODE_IGNORED;
|
||||
}
|
||||
final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
|
||||
@@ -3347,16 +3350,16 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isPrivileged;
|
||||
RestrictionBypass bypass;
|
||||
try {
|
||||
isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
|
||||
bypass = verifyAndGetBypass(uid, packageName, featureId);
|
||||
} catch (SecurityException e) {
|
||||
Slog.e(TAG, "Cannot finishOperation", e);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
Op op = getOpLocked(code, uid, resolvedPackageName, featureId, isPrivileged, true);
|
||||
Op op = getOpLocked(code, uid, resolvedPackageName, featureId, bypass, true);
|
||||
if (op == null) {
|
||||
return;
|
||||
}
|
||||
@@ -3617,7 +3620,22 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that package belongs to uid and return whether the package is privileged.
|
||||
* Create a restriction description matching the properties of the package.
|
||||
*
|
||||
* @param context A context to use
|
||||
* @param pkg The package to create the restriction description for
|
||||
*
|
||||
* @return The restriction matching the package
|
||||
*/
|
||||
private RestrictionBypass getBypassforPackage(@NonNull AndroidPackage pkg) {
|
||||
return new RestrictionBypass(pkg.isPrivileged(), mContext.checkPermission(
|
||||
android.Manifest.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS, -1, pkg.getUid())
|
||||
== PackageManager.PERMISSION_GRANTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that package belongs to uid and return the {@link RestrictionBypass bypass
|
||||
* description} for the package.
|
||||
*
|
||||
* @param uid The uid the package belongs to
|
||||
* @param packageName The package the might belong to the uid
|
||||
@@ -3625,11 +3643,11 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
*
|
||||
* @return {@code true} iff the package is privileged
|
||||
*/
|
||||
private boolean verifyAndGetIsPrivileged(int uid, String packageName,
|
||||
private @Nullable RestrictionBypass verifyAndGetBypass(int uid, String packageName,
|
||||
@Nullable String featureId) {
|
||||
if (uid == Process.ROOT_UID) {
|
||||
// For backwards compatibility, don't check package name for root UID.
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Do not check if uid/packageName/featureId is already known
|
||||
@@ -3638,13 +3656,14 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
if (uidState != null && uidState.pkgOps != null) {
|
||||
Ops ops = uidState.pkgOps.get(packageName);
|
||||
|
||||
if (ops != null && (featureId == null || ops.knownFeatureIds.contains(featureId))) {
|
||||
return ops.isPrivileged;
|
||||
if (ops != null && (featureId == null || ops.knownFeatureIds.contains(featureId))
|
||||
&& ops.bypass != null) {
|
||||
return ops.bypass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isPrivileged = false;
|
||||
RestrictionBypass bypass = null;
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
int pkgUid;
|
||||
@@ -3668,14 +3687,14 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
|
||||
pkgUid = UserHandle.getUid(
|
||||
UserHandle.getUserId(uid), UserHandle.getAppId(pkg.getUid()));
|
||||
isPrivileged = pkg.isPrivileged();
|
||||
bypass = getBypassforPackage(pkg);
|
||||
} else {
|
||||
// Allow any feature id for resolvable uids
|
||||
isFeatureIdValid = true;
|
||||
|
||||
pkgUid = resolveUid(packageName);
|
||||
if (pkgUid >= 0) {
|
||||
isPrivileged = false;
|
||||
bypass = RestrictionBypass.UNRESTRICTED;
|
||||
}
|
||||
}
|
||||
if (pkgUid != uid) {
|
||||
@@ -3692,7 +3711,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
|
||||
return isPrivileged;
|
||||
return bypass;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3701,13 +3720,13 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
* @param uid The uid the package belongs to
|
||||
* @param packageName The name of the package
|
||||
* @param featureId The feature in the package
|
||||
* @param isPrivileged If the package is privilidged (ignored if {@code edit} is false)
|
||||
* @param bypass When to bypass certain op restrictions (can be null if edit == false)
|
||||
* @param edit If an ops does not exist, create the ops?
|
||||
|
||||
* @return
|
||||
* @return The ops
|
||||
*/
|
||||
private Ops getOpsRawLocked(int uid, String packageName, @Nullable String featureId,
|
||||
boolean isPrivileged, boolean edit) {
|
||||
private Ops getOpsLocked(int uid, String packageName, @Nullable String featureId,
|
||||
@Nullable RestrictionBypass bypass, boolean edit) {
|
||||
UidState uidState = getUidStateLocked(uid, edit);
|
||||
if (uidState == null) {
|
||||
return null;
|
||||
@@ -3725,53 +3744,18 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
if (!edit) {
|
||||
return null;
|
||||
}
|
||||
ops = new Ops(packageName, uidState, isPrivileged);
|
||||
uidState.pkgOps.put(packageName, ops);
|
||||
}
|
||||
if (edit && featureId != null) {
|
||||
ops.knownFeatureIds.add(featureId);
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state of all ops for a package.
|
||||
*
|
||||
* <p>Usually callers should use {@link #getOpLocked} and not call this directly.
|
||||
*
|
||||
* @param uid The uid the of the package
|
||||
* @param packageName The package name for which to get the state for
|
||||
* @param featureId The feature in the package
|
||||
* @param edit Iff {@code true} create the {@link Ops} object if not yet created
|
||||
* @param isPrivileged Whether the package is privileged or not
|
||||
*
|
||||
* @return The {@link Ops state} of all ops for the package
|
||||
*/
|
||||
private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
|
||||
@Nullable String featureId, boolean edit, boolean isPrivileged) {
|
||||
UidState uidState = getUidStateLocked(uid, edit);
|
||||
if (uidState == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (uidState.pkgOps == null) {
|
||||
if (!edit) {
|
||||
return null;
|
||||
}
|
||||
uidState.pkgOps = new ArrayMap<>();
|
||||
}
|
||||
|
||||
Ops ops = uidState.pkgOps.get(packageName);
|
||||
if (ops == null) {
|
||||
if (!edit) {
|
||||
return null;
|
||||
}
|
||||
ops = new Ops(packageName, uidState, isPrivileged);
|
||||
ops = new Ops(packageName, uidState);
|
||||
uidState.pkgOps.put(packageName, ops);
|
||||
}
|
||||
|
||||
if (edit && featureId != null) {
|
||||
ops.knownFeatureIds.add(featureId);
|
||||
if (edit) {
|
||||
if (bypass != null) {
|
||||
ops.bypass = bypass;
|
||||
}
|
||||
|
||||
if (featureId != null) {
|
||||
ops.knownFeatureIds.add(featureId);
|
||||
}
|
||||
}
|
||||
|
||||
return ops;
|
||||
@@ -3800,15 +3784,14 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
* @param uid The uid the of the package
|
||||
* @param packageName The package name for which to get the state for
|
||||
* @param featureId The feature in the package
|
||||
* @param isPrivileged Whether the package is privileged or not (only used if {@code edit
|
||||
* == true})
|
||||
* @param bypass When to bypass certain op restrictions (can be null if edit == false)
|
||||
* @param edit Iff {@code true} create the {@link Op} object if not yet created
|
||||
*
|
||||
* @return The {@link Op state} of the op
|
||||
*/
|
||||
private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
|
||||
@Nullable String featureId, boolean isPrivileged, boolean edit) {
|
||||
Ops ops = getOpsRawNoVerifyLocked(uid, packageName, featureId, edit, isPrivileged);
|
||||
@Nullable String featureId, @Nullable RestrictionBypass bypass, boolean edit) {
|
||||
Ops ops = getOpsLocked(uid, packageName, featureId, bypass, edit);
|
||||
if (ops == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -3839,7 +3822,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
|
||||
private boolean isOpRestrictedLocked(int uid, int code, String packageName,
|
||||
@Nullable String featureId, boolean isPrivileged) {
|
||||
@Nullable RestrictionBypass appBypass) {
|
||||
int userHandle = UserHandle.getUserId(uid);
|
||||
final int restrictionSetCount = mOpUserRestrictions.size();
|
||||
|
||||
@@ -3848,12 +3831,15 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
// package is exempt from the restriction.
|
||||
ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
|
||||
if (restrictionState.hasRestriction(code, packageName, userHandle)) {
|
||||
if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
|
||||
RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
|
||||
if (opBypass != null) {
|
||||
// If we are the system, bypass user restrictions for certain codes
|
||||
synchronized (this) {
|
||||
Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
|
||||
true /* edit */);
|
||||
if ((ops != null) && ops.isPrivileged) {
|
||||
if (opBypass.isPrivileged && appBypass != null && appBypass.isPrivileged) {
|
||||
return false;
|
||||
}
|
||||
if (opBypass.isRecordAudioRestrictionExcept && appBypass != null
|
||||
&& appBypass.isRecordAudioRestrictionExcept) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -4043,28 +4029,6 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
throws NumberFormatException, XmlPullParserException, IOException {
|
||||
int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
|
||||
final UidState uidState = getUidStateLocked(uid, true);
|
||||
String isPrivilegedString = parser.getAttributeValue(null, "p");
|
||||
boolean isPrivileged = false;
|
||||
if (isPrivilegedString == null) {
|
||||
try {
|
||||
IPackageManager packageManager = ActivityThread.getPackageManager();
|
||||
if (packageManager != null) {
|
||||
ApplicationInfo appInfo = ActivityThread.getPackageManager()
|
||||
.getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
|
||||
if (appInfo != null) {
|
||||
isPrivileged = (appInfo.privateFlags
|
||||
& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
|
||||
}
|
||||
} else {
|
||||
// Could not load data, don't add to cache so it will be loaded later.
|
||||
return;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Could not contact PackageManager", e);
|
||||
}
|
||||
} else {
|
||||
isPrivileged = Boolean.parseBoolean(isPrivilegedString);
|
||||
}
|
||||
int outerDepth = parser.getDepth();
|
||||
int type;
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
@@ -4074,7 +4038,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
String tagName = parser.getName();
|
||||
if (tagName.equals("op")) {
|
||||
readOp(parser, uidState, pkgName, isPrivileged);
|
||||
readOp(parser, uidState, pkgName);
|
||||
} else {
|
||||
Slog.w(TAG, "Unknown element under <pkg>: "
|
||||
+ parser.getName());
|
||||
@@ -4108,8 +4072,8 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void readOp(XmlPullParser parser, @NonNull UidState uidState,
|
||||
@NonNull String pkgName, boolean isPrivileged) throws NumberFormatException,
|
||||
private void readOp(XmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName)
|
||||
throws NumberFormatException,
|
||||
XmlPullParserException, IOException {
|
||||
int opCode = Integer.parseInt(parser.getAttributeValue(null, "n"));
|
||||
if (isIgnoredAppOp(opCode)) {
|
||||
@@ -4143,7 +4107,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
Ops ops = uidState.pkgOps.get(pkgName);
|
||||
if (ops == null) {
|
||||
ops = new Ops(pkgName, uidState, isPrivileged);
|
||||
ops = new Ops(pkgName, uidState);
|
||||
uidState.pkgOps.put(pkgName, ops);
|
||||
}
|
||||
ops.put(op.op, op);
|
||||
@@ -4235,17 +4199,6 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
out.startTag(null, "uid");
|
||||
out.attribute(null, "n", Integer.toString(pkg.getUid()));
|
||||
synchronized (this) {
|
||||
Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), null,
|
||||
false /* isPrivileged */, false /* edit */);
|
||||
// Should always be present as the list of PackageOps is generated
|
||||
// from Ops.
|
||||
if (ops != null) {
|
||||
out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
|
||||
} else {
|
||||
out.attribute(null, "p", Boolean.toString(false));
|
||||
}
|
||||
}
|
||||
List<AppOpsManager.OpEntry> ops = pkg.getOps();
|
||||
for (int j=0; j<ops.size(); j++) {
|
||||
AppOpsManager.OpEntry op = ops.get(j);
|
||||
@@ -5574,7 +5527,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
// TODO moltmann: Allow to check for feature op activeness
|
||||
synchronized (AppOpsService.this) {
|
||||
Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false, false);
|
||||
Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false);
|
||||
if (pkgOps == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user