Merge "Note RECEIVE_AMBIENT_TRIGGER_AUDIO in the SoundTrigger" into tm-dev

This commit is contained in:
Nate Myren
2022-05-11 22:00:35 +00:00
committed by Android (Google) Code Review
11 changed files with 101 additions and 14 deletions

View File

@@ -1335,9 +1335,17 @@ public class AppOpsManager {
public static final int OP_ACCESS_RESTRICTED_SETTINGS =
AppProtoEnums.APP_OP_ACCESS_RESTRICTED_SETTINGS;
/**
* Receive microphone audio from an ambient sound detection event
*
* @hide
*/
public static final int OP_RECEIVE_AMBIENT_TRIGGER_AUDIO =
AppProtoEnums.APP_OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final int _NUM_OP = 120;
public static final int _NUM_OP = 121;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1800,6 +1808,14 @@ public class AppOpsManager {
public static final String OPSTR_ACCESS_RESTRICTED_SETTINGS =
"android:access_restricted_settings";
/**
* Receive microphone audio from an ambient sound detection event
*
* @hide
*/
public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO =
"android:receive_ambient_trigger_audio";
/** {@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} */
@@ -2021,6 +2037,7 @@ public class AppOpsManager {
OP_ESTABLISH_VPN_SERVICE, // OP_ESTABLISH_VPN_SERVICE
OP_ESTABLISH_VPN_MANAGER, // OP_ESTABLISH_VPN_MANAGER
OP_ACCESS_RESTRICTED_SETTINGS, // OP_ACCESS_RESTRICTED_SETTINGS
OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -2147,6 +2164,7 @@ public class AppOpsManager {
OPSTR_ESTABLISH_VPN_SERVICE,
OPSTR_ESTABLISH_VPN_MANAGER,
OPSTR_ACCESS_RESTRICTED_SETTINGS,
OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO,
};
/**
@@ -2274,6 +2292,7 @@ public class AppOpsManager {
"ESTABLISH_VPN_SERVICE",
"ESTABLISH_VPN_MANAGER",
"ACCESS_RESTRICTED_SETTINGS",
"RECEIVE_SOUNDTRIGGER_AUDIO",
};
/**
@@ -2402,6 +2421,7 @@ public class AppOpsManager {
null, // no permission for OP_ESTABLISH_VPN_SERVICE
null, // no permission for OP_ESTABLISH_VPN_MANAGER
null, // no permission for OP_ACCESS_RESTRICTED_SETTINGS,
null, // no permission for OP_RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -2529,7 +2549,8 @@ public class AppOpsManager {
null, // NEARBY_WIFI_DEVICES
null, // ESTABLISH_VPN_SERVICE
null, // ESTABLISH_VPN_MANAGER
null, // ACCESS_RESTRICTED_SETTINGS,
null, // ACCESS_RESTRICTED_SETTINGS
null, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -2656,7 +2677,8 @@ public class AppOpsManager {
null, // NEARBY_WIFI_DEVICES
null, // ESTABLISH_VPN_SERVICE
null, // ESTABLISH_VPN_MANAGER
null, // ACCESS_RESTRICTED_SETTINGS,
null, // ACCESS_RESTRICTED_SETTINGS
null, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -2765,7 +2787,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ERRORED, // OP_NO_ISOLATED_STORAGE
AppOpsManager.MODE_ALLOWED, // PHONE_CALL_MICROPHONE
AppOpsManager.MODE_ALLOWED, // PHONE_CALL_CAMERA
AppOpsManager.MODE_ALLOWED, // OP_RECORD_AUDIO_HOTWORD
AppOpsManager.MODE_ALLOWED, // RECORD_AUDIO_HOTWORD
AppOpsManager.MODE_DEFAULT, // MANAGE_ONGOING_CALLS
AppOpsManager.MODE_DEFAULT, // MANAGE_CREDENTIALS
AppOpsManager.MODE_DEFAULT, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
@@ -2783,6 +2805,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_SERVICE
AppOpsManager.MODE_ALLOWED, // ESTABLISH_VPN_MANAGER
AppOpsManager.MODE_ALLOWED, // ACCESS_RESTRICTED_SETTINGS,
AppOpsManager.MODE_ALLOWED, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -2913,6 +2936,7 @@ public class AppOpsManager {
false, // OP_ESTABLISH_VPN_SERVICE
false, // OP_ESTABLISH_VPN_MANAGER
true, // ACCESS_RESTRICTED_SETTINGS
false, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**
@@ -3040,6 +3064,7 @@ public class AppOpsManager {
false, // OP_ESTABLISH_VPN_SERVICE
false, // OP_ESTABLISH_VPN_MANAGER
true, // ACCESS_RESTRICTED_SETTINGS
false, // RECEIVE_SOUNDTRIGGER_AUDIO
};
/**

View File

@@ -30,6 +30,7 @@ import static android.app.AppOpsManager.OPSTR_COARSE_LOCATION;
import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
import static android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA;
import static android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE;
import static android.app.AppOpsManager.OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
@@ -137,6 +138,7 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
private static final List<String> MIC_OPS = List.of(
OPSTR_PHONE_CALL_MICROPHONE,
OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO,
OPSTR_RECORD_AUDIO
);
@@ -147,6 +149,7 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
private static @NonNull String getGroupForOp(String op) {
switch (op) {
case OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO:
case OPSTR_RECORD_AUDIO:
return MICROPHONE;
case OPSTR_CAMERA:

View File

@@ -102,6 +102,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
AppOpsManager.OP_PHONE_CALL_CAMERA,
AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
AppOpsManager.OP_RECORD_AUDIO,
AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
AppOpsManager.OP_PHONE_CALL_MICROPHONE,
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION
@@ -535,7 +536,8 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
}
private boolean isOpMicrophone(int op) {
return op == AppOpsManager.OP_RECORD_AUDIO || op == AppOpsManager.OP_PHONE_CALL_MICROPHONE;
return op == AppOpsManager.OP_RECORD_AUDIO || op == AppOpsManager.OP_PHONE_CALL_MICROPHONE
|| op == AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
}
protected class H extends Handler {

View File

@@ -58,7 +58,8 @@ class PrivacyItemController @Inject constructor(
internal companion object {
val OPS_MIC_CAMERA = intArrayOf(AppOpsManager.OP_CAMERA,
AppOpsManager.OP_PHONE_CALL_CAMERA, AppOpsManager.OP_RECORD_AUDIO,
AppOpsManager.OP_PHONE_CALL_MICROPHONE)
AppOpsManager.OP_PHONE_CALL_MICROPHONE,
AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO)
val OPS_LOCATION = intArrayOf(
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION)
@@ -315,6 +316,7 @@ class PrivacyItemController @Inject constructor(
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION -> PrivacyType.TYPE_LOCATION
AppOpsManager.OP_PHONE_CALL_MICROPHONE,
AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
else -> return null
}

View File

@@ -43,6 +43,7 @@ import static android.app.AppOpsManager.OP_FLAG_SELF;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
@@ -3849,7 +3850,7 @@ public class AppOpsService extends IAppOpsService.Stub {
// the data gated by OP_RECORD_AUDIO.
//
// TODO: Revert this change before Android 12.
if (code == OP_RECORD_AUDIO_HOTWORD) {
if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO) {
int result = checkOperation(OP_RECORD_AUDIO, uid, packageName);
if (result != AppOpsManager.MODE_ALLOWED) {
return new SyncNotedAppOp(result, code, attributionTag, packageName);

View File

@@ -34,6 +34,7 @@ import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXY;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
import static android.app.AppOpsManager.OP_PHONE_CALL_MICROPHONE;
import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.flagsToString;
import static android.app.AppOpsManager.getUidStateName;
@@ -133,7 +134,7 @@ final class DiscreteRegistry {
private static final String PROPERTY_DISCRETE_OPS_LIST = "discrete_history_ops_cslist";
private static final String DEFAULT_DISCRETE_OPS = OP_FINE_LOCATION + "," + OP_COARSE_LOCATION
+ "," + OP_CAMERA + "," + OP_RECORD_AUDIO + "," + OP_PHONE_CALL_MICROPHONE + ","
+ OP_PHONE_CALL_CAMERA;
+ OP_PHONE_CALL_CAMERA + "," + OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
private static final long DEFAULT_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(7).toMillis();
private static final long MAXIMUM_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(30).toMillis();
private static final long DEFAULT_DISCRETE_HISTORY_QUANTIZATION =

View File

@@ -17,6 +17,7 @@
package com.android.server.pm.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
/**
@@ -104,6 +105,20 @@ public interface LegacyPermissionManagerInternal {
*/
void scheduleReadDefaultPermissionExceptions();
/**
* Check whether a particular package should have access to the microphone data from the
* SoundTrigger.
*
* @param uid the uid of the package you are checking against
* @param packageName the name of the package you are checking against
* @param attributionTag the attributionTag to attach to the app op transaction
* @param reason the reason to attach to the app op transaction
* @return {@code PERMISSION_GRANTED} if the permission is granted,
* or {@code PERMISSION_SOFT/HARD DENIED otherwise
*/
int checkSoundTriggerRecordAudioPermissionForDataDelivery(int uid,
@NonNull String packageName, @Nullable String attributionTag, @NonNull String reason);
/**
* Provider for package names.
*/

View File

@@ -16,12 +16,15 @@
package com.android.server.pm.permission;
import static android.Manifest.permission.RECORD_AUDIO;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -399,6 +402,21 @@ public class LegacyPermissionManagerService extends ILegacyPermissionManager.Stu
public void scheduleReadDefaultPermissionExceptions() {
mDefaultPermissionGrantPolicy.scheduleReadDefaultPermissionExceptions();
}
@Override
public int checkSoundTriggerRecordAudioPermissionForDataDelivery(int uid,
@NonNull String packageName, @Nullable String attributionTag,
@NonNull String reason) {
int result = PermissionChecker.checkPermissionForPreflight(mContext, RECORD_AUDIO, -1,
uid, packageName);
if (result != PermissionChecker.PERMISSION_GRANTED) {
return result;
}
mContext.getSystemService(AppOpsManager.class).noteOpNoThrow(
AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, uid, packageName,
attributionTag, reason);
return result;
}
}
/**

View File

@@ -87,8 +87,8 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
private final VoiceInteractionManagerInternal mVoiceInteractionManagerInternal;
/**
* Whether this device allows only the HotwordDetectionService to use OP_RECORD_AUDIO_HOTWORD
* which doesn't incur the privacy indicator.
* Whether this device allows only the HotwordDetectionService to use
* OP_RECORD_AUDIO_HOTWORD which doesn't incur the privacy indicator.
*/
private final boolean mIsHotwordDetectionServiceRequired;
@@ -428,8 +428,8 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
if (!mIsHotwordDetectionServiceRequired) {
return code;
}
// Only the HotwordDetectionService can use the HOTWORD op which doesn't incur the
// privacy indicator. Downgrade to standard RECORD_AUDIO for other processes.
// Only the HotwordDetectionService can use the RECORD_AUDIO_HOTWORD op which doesn't
// incur the privacy indicator. Downgrade to standard RECORD_AUDIO for other processes.
final HotwordDetectionServiceIdentity hotwordDetectionServiceIdentity =
mVoiceInteractionManagerInternal.getHotwordDetectionServiceIdentity();
if (hotwordDetectionServiceIdentity != null

View File

@@ -25,6 +25,7 @@ import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
import static android.app.AppOpsManager.OP_PHONE_CALL_MICROPHONE;
import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -1067,6 +1068,10 @@ public final class SensorPrivacyService extends SystemService {
mAppOpsRestrictionToken);
mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_MICROPHONE, enabled,
mAppOpsRestrictionToken);
// We don't show the dialog for RECEIVE_SOUNDTRIGGER_AUDIO, but still want to
// restrict it when the microphone is disabled
mAppOpsManagerInternal.setGlobalRestriction(OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
enabled, mAppOpsRestrictionToken);
break;
case CAMERA:
mAppOpsManagerInternal.setGlobalRestriction(OP_CAMERA, enabled,

View File

@@ -41,6 +41,9 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import com.android.server.LocalServices;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
import java.io.PrintWriter;
import java.util.Objects;
@@ -120,8 +123,7 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware
* Throws a {@link SecurityException} iff the originator has permission to receive data.
*/
void enforcePermissionsForDataDelivery(@NonNull Identity identity, @NonNull String reason) {
enforcePermissionForDataDelivery(mContext, identity, RECORD_AUDIO,
reason);
enforceSoundTriggerRecordAudioPermissionForDataDelivery(identity, reason);
enforcePermissionForDataDelivery(mContext, identity, CAPTURE_AUDIO_HOTWORD,
reason);
}
@@ -147,6 +149,19 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware
}
}
private static void enforceSoundTriggerRecordAudioPermissionForDataDelivery(
@NonNull Identity identity, @NonNull String reason) {
LegacyPermissionManagerInternal lpmi =
LocalServices.getService(LegacyPermissionManagerInternal.class);
final int status = lpmi.checkSoundTriggerRecordAudioPermissionForDataDelivery(identity.uid,
identity.packageName, identity.attributionTag, reason);
if (status != PermissionChecker.PERMISSION_GRANTED) {
throw new SecurityException(
String.format("Failed to obtain permission RECORD_AUDIO for identity %s",
ObjectPrinter.print(identity, 16)));
}
}
/**
* Throws a {@link SecurityException} if originator permanently doesn't have the given
* permission.