Merge "Grant HotwordDetectionService RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD." into sc-dev
This commit is contained in:
@@ -16,9 +16,12 @@
|
|||||||
|
|
||||||
package android.service.voice;
|
package android.service.voice;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.Immutable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
@@ -46,4 +49,38 @@ public abstract class VoiceInteractionManagerInternal {
|
|||||||
* Returns whether the given package is currently in an active session
|
* Returns whether the given package is currently in an active session
|
||||||
*/
|
*/
|
||||||
public abstract boolean hasActiveSession(String packageName);
|
public abstract boolean hasActiveSession(String packageName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the identity of the currently active HotwordDetectionService.
|
||||||
|
*
|
||||||
|
* @see HotwordDetectionServiceIdentity
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public abstract HotwordDetectionServiceIdentity getHotwordDetectionServiceIdentity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the uids of the currently active
|
||||||
|
* {@link android.service.voice.HotwordDetectionService} and its owning package. The
|
||||||
|
* HotwordDetectionService is an isolated service, so it has a separate uid.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
public static class HotwordDetectionServiceIdentity {
|
||||||
|
private final int mIsolatedUid;
|
||||||
|
private final int mOwnerUid;
|
||||||
|
|
||||||
|
public HotwordDetectionServiceIdentity(int isolatedUid, int ownerUid) {
|
||||||
|
mIsolatedUid = isolatedUid;
|
||||||
|
mOwnerUid = ownerUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the uid of the currently active isolated process hosting the service. */
|
||||||
|
public int getIsolatedUid() {
|
||||||
|
return mIsolatedUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the uid of the package that provides the HotwordDetectionService. */
|
||||||
|
public int getOwnerUid() {
|
||||||
|
return mOwnerUid;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,9 @@
|
|||||||
package com.android.server.pm.permission;
|
package com.android.server.pm.permission;
|
||||||
|
|
||||||
import static android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY;
|
import static android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY;
|
||||||
|
import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
|
||||||
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
|
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
|
||||||
|
import static android.Manifest.permission.RECORD_AUDIO;
|
||||||
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||||
import static android.app.AppOpsManager.MODE_ALLOWED;
|
import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||||
import static android.app.AppOpsManager.MODE_ERRORED;
|
import static android.app.AppOpsManager.MODE_ERRORED;
|
||||||
@@ -148,6 +150,7 @@ import com.android.server.pm.UserManagerInternal;
|
|||||||
import com.android.server.pm.UserManagerService;
|
import com.android.server.pm.UserManagerService;
|
||||||
import com.android.server.pm.parsing.PackageInfoUtils;
|
import com.android.server.pm.parsing.PackageInfoUtils;
|
||||||
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
import com.android.server.pm.parsing.pkg.AndroidPackage;
|
||||||
|
import com.android.server.pm.permission.PermissionManagerServiceInternal.HotwordDetectionServiceProvider;
|
||||||
import com.android.server.pm.permission.PermissionManagerServiceInternal.OnRuntimePermissionStateChangedListener;
|
import com.android.server.pm.permission.PermissionManagerServiceInternal.OnRuntimePermissionStateChangedListener;
|
||||||
import com.android.server.policy.PermissionPolicyInternal;
|
import com.android.server.policy.PermissionPolicyInternal;
|
||||||
import com.android.server.policy.SoftRestrictedPermissionPolicy;
|
import com.android.server.policy.SoftRestrictedPermissionPolicy;
|
||||||
@@ -308,6 +311,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final OnPermissionChangeListeners mOnPermissionChangeListeners;
|
private final OnPermissionChangeListeners mOnPermissionChangeListeners;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private HotwordDetectionServiceProvider mHotwordDetectionServiceProvider;
|
||||||
|
|
||||||
// TODO: Take a look at the methods defined in the callback.
|
// TODO: Take a look at the methods defined in the callback.
|
||||||
// The callback was initially created to support the split between permission
|
// The callback was initially created to support the split between permission
|
||||||
// manager and the package manager. However, it's started to be used for other
|
// manager and the package manager. However, it's started to be used for other
|
||||||
@@ -5200,6 +5206,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
|||||||
public int[] getGidsForUid(int uid) {
|
public int[] getGidsForUid(int uid) {
|
||||||
return PermissionManagerService.this.getGidsForUid(uid);
|
return PermissionManagerService.this.getGidsForUid(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHotwordDetectionServiceProvider(HotwordDetectionServiceProvider provider) {
|
||||||
|
mHotwordDetectionServiceProvider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HotwordDetectionServiceProvider getHotwordDetectionServiceProvider() {
|
||||||
|
return mHotwordDetectionServiceProvider;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -5476,10 +5492,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
|||||||
|
|
||||||
private final @NonNull Context mContext;
|
private final @NonNull Context mContext;
|
||||||
private final @NonNull AppOpsManager mAppOpsManager;
|
private final @NonNull AppOpsManager mAppOpsManager;
|
||||||
|
private final @NonNull PermissionManagerServiceInternal mPermissionManagerServiceInternal;
|
||||||
|
|
||||||
PermissionCheckerService(@NonNull Context context) {
|
PermissionCheckerService(@NonNull Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
|
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
|
||||||
|
mPermissionManagerServiceInternal =
|
||||||
|
LocalServices.getService(PermissionManagerServiceInternal.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -5492,8 +5511,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
|||||||
Objects.requireNonNull(attributionSourceState);
|
Objects.requireNonNull(attributionSourceState);
|
||||||
final AttributionSource attributionSource = new AttributionSource(
|
final AttributionSource attributionSource = new AttributionSource(
|
||||||
attributionSourceState);
|
attributionSourceState);
|
||||||
final int result = checkPermission(mContext, permission, attributionSource, message,
|
final int result = checkPermission(mContext, mPermissionManagerServiceInternal,
|
||||||
forDataDelivery, startDataDelivery, fromDatasource, attributedOp);
|
permission, attributionSource, message, forDataDelivery, startDataDelivery,
|
||||||
|
fromDatasource, attributedOp);
|
||||||
// Finish any started op if some step in the attribution chain failed.
|
// Finish any started op if some step in the attribution chain failed.
|
||||||
if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED
|
if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED
|
||||||
&& result != PermissionChecker.PERMISSION_SOFT_DENIED) {
|
&& result != PermissionChecker.PERMISSION_SOFT_DENIED) {
|
||||||
@@ -5582,10 +5602,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PermissionCheckerManager.PermissionResult
|
@PermissionCheckerManager.PermissionResult
|
||||||
private static int checkPermission(@NonNull Context context, @NonNull String permission,
|
private static int checkPermission(@NonNull Context context,
|
||||||
@NonNull AttributionSource attributionSource, @Nullable String message,
|
@NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
|
||||||
boolean forDataDelivery, boolean startDataDelivery, boolean fromDatasource,
|
@NonNull String permission, @NonNull AttributionSource attributionSource,
|
||||||
int attributedOp) {
|
@Nullable String message, boolean forDataDelivery, boolean startDataDelivery,
|
||||||
|
boolean fromDatasource, int attributedOp) {
|
||||||
PermissionInfo permissionInfo = sPlatformPermissions.get(permission);
|
PermissionInfo permissionInfo = sPlatformPermissions.get(permission);
|
||||||
|
|
||||||
if (permissionInfo == null) {
|
if (permissionInfo == null) {
|
||||||
@@ -5602,22 +5623,25 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (permissionInfo.isAppOp()) {
|
if (permissionInfo.isAppOp()) {
|
||||||
return checkAppOpPermission(context, permission, attributionSource, message,
|
return checkAppOpPermission(context, permissionManagerServiceInt, permission,
|
||||||
forDataDelivery, fromDatasource);
|
attributionSource, message, forDataDelivery, fromDatasource);
|
||||||
}
|
}
|
||||||
if (permissionInfo.isRuntime()) {
|
if (permissionInfo.isRuntime()) {
|
||||||
return checkRuntimePermission(context, permission, attributionSource, message,
|
return checkRuntimePermission(context, permissionManagerServiceInt, permission,
|
||||||
forDataDelivery, startDataDelivery, fromDatasource, attributedOp);
|
attributionSource, message, forDataDelivery, startDataDelivery,
|
||||||
|
fromDatasource, attributedOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fromDatasource && !checkPermission(context, permission, attributionSource.getUid(),
|
if (!fromDatasource && !checkPermission(context, permissionManagerServiceInt,
|
||||||
|
permission, attributionSource.getUid(),
|
||||||
attributionSource.getRenouncedPermissions())) {
|
attributionSource.getRenouncedPermissions())) {
|
||||||
return PermissionChecker.PERMISSION_HARD_DENIED;
|
return PermissionChecker.PERMISSION_HARD_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attributionSource.getNext() != null) {
|
if (attributionSource.getNext() != null) {
|
||||||
return checkPermission(context, permission, attributionSource.getNext(), message,
|
return checkPermission(context, permissionManagerServiceInt, permission,
|
||||||
forDataDelivery, startDataDelivery, /*fromDatasource*/ false, attributedOp);
|
attributionSource.getNext(), message, forDataDelivery, startDataDelivery,
|
||||||
|
/*fromDatasource*/ false, attributedOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return PermissionChecker.PERMISSION_GRANTED;
|
return PermissionChecker.PERMISSION_GRANTED;
|
||||||
@@ -5625,6 +5649,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
|||||||
|
|
||||||
@PermissionCheckerManager.PermissionResult
|
@PermissionCheckerManager.PermissionResult
|
||||||
private static int checkAppOpPermission(@NonNull Context context,
|
private static int checkAppOpPermission(@NonNull Context context,
|
||||||
|
@NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
|
||||||
@NonNull String permission, @NonNull AttributionSource attributionSource,
|
@NonNull String permission, @NonNull AttributionSource attributionSource,
|
||||||
@Nullable String message, boolean forDataDelivery, boolean fromDatasource) {
|
@Nullable String message, boolean forDataDelivery, boolean fromDatasource) {
|
||||||
final int op = AppOpsManager.permissionToOpCode(permission);
|
final int op = AppOpsManager.permissionToOpCode(permission);
|
||||||
@@ -5668,13 +5693,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
|||||||
return PermissionChecker.PERMISSION_HARD_DENIED;
|
return PermissionChecker.PERMISSION_HARD_DENIED;
|
||||||
}
|
}
|
||||||
case AppOpsManager.MODE_DEFAULT: {
|
case AppOpsManager.MODE_DEFAULT: {
|
||||||
if (!skipCurrentChecks && !checkPermission(context, permission,
|
if (!skipCurrentChecks && !checkPermission(context,
|
||||||
attributionSource.getUid(), attributionSource
|
permissionManagerServiceInt, permission, attributionSource.getUid(),
|
||||||
.getRenouncedPermissions())) {
|
attributionSource.getRenouncedPermissions())) {
|
||||||
return PermissionChecker.PERMISSION_HARD_DENIED;
|
return PermissionChecker.PERMISSION_HARD_DENIED;
|
||||||
}
|
}
|
||||||
if (next != null && !checkPermission(context, permission,
|
if (next != null && !checkPermission(context, permissionManagerServiceInt,
|
||||||
next.getUid(), next.getRenouncedPermissions())) {
|
permission, next.getUid(), next.getRenouncedPermissions())) {
|
||||||
return PermissionChecker.PERMISSION_HARD_DENIED;
|
return PermissionChecker.PERMISSION_HARD_DENIED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5689,6 +5714,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int checkRuntimePermission(@NonNull Context context,
|
private static int checkRuntimePermission(@NonNull Context context,
|
||||||
|
@NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
|
||||||
@NonNull String permission, @NonNull AttributionSource attributionSource,
|
@NonNull String permission, @NonNull AttributionSource attributionSource,
|
||||||
@Nullable String message, boolean forDataDelivery, boolean startDataDelivery,
|
@Nullable String message, boolean forDataDelivery, boolean startDataDelivery,
|
||||||
boolean fromDatasource, int attributedOp) {
|
boolean fromDatasource, int attributedOp) {
|
||||||
@@ -5713,13 +5739,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we already checked the permission for this one, skip the work
|
// If we already checked the permission for this one, skip the work
|
||||||
if (!skipCurrentChecks && !checkPermission(context, permission,
|
if (!skipCurrentChecks && !checkPermission(context, permissionManagerServiceInt,
|
||||||
current.getUid(), current.getRenouncedPermissions())) {
|
permission, current.getUid(), current.getRenouncedPermissions())) {
|
||||||
return PermissionChecker.PERMISSION_HARD_DENIED;
|
return PermissionChecker.PERMISSION_HARD_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next != null && !checkPermission(context, permission,
|
if (next != null && !checkPermission(context, permissionManagerServiceInt,
|
||||||
next.getUid(), next.getRenouncedPermissions())) {
|
permission, next.getUid(), next.getRenouncedPermissions())) {
|
||||||
return PermissionChecker.PERMISSION_HARD_DENIED;
|
return PermissionChecker.PERMISSION_HARD_DENIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5774,10 +5800,26 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkPermission(@NonNull Context context, @NonNull String permission,
|
private static boolean checkPermission(@NonNull Context context,
|
||||||
int uid, @NonNull Set<String> renouncedPermissions) {
|
@NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
|
||||||
final boolean permissionGranted = context.checkPermission(permission, /*pid*/ -1,
|
@NonNull String permission, int uid, @NonNull Set<String> renouncedPermissions) {
|
||||||
|
boolean permissionGranted = context.checkPermission(permission, /*pid*/ -1,
|
||||||
uid) == PackageManager.PERMISSION_GRANTED;
|
uid) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
|
||||||
|
// Override certain permissions checks for the HotwordDetectionService. This service is
|
||||||
|
// an isolated service, which ordinarily cannot hold permissions.
|
||||||
|
// There's probably a cleaner, more generalizable way to do this. For now, this is
|
||||||
|
// the only use case for this, so simply override here.
|
||||||
|
if (!permissionGranted
|
||||||
|
&& Process.isIsolated(uid) // simple check which fails-fast for the common case
|
||||||
|
&& (permission.equals(RECORD_AUDIO)
|
||||||
|
|| permission.equals(CAPTURE_AUDIO_HOTWORD))) {
|
||||||
|
HotwordDetectionServiceProvider hotwordServiceProvider =
|
||||||
|
permissionManagerServiceInt.getHotwordDetectionServiceProvider();
|
||||||
|
permissionGranted = hotwordServiceProvider != null
|
||||||
|
&& uid == hotwordServiceProvider.getUid();
|
||||||
|
}
|
||||||
|
|
||||||
if (permissionGranted && renouncedPermissions.contains(permission)
|
if (permissionGranted && renouncedPermissions.contains(permission)
|
||||||
&& context.checkPermission(Manifest.permission.RENOUNCE_PERMISSIONS,
|
&& context.checkPermission(Manifest.permission.RENOUNCE_PERMISSIONS,
|
||||||
/*pid*/ -1, uid) == PackageManager.PERMISSION_GRANTED) {
|
/*pid*/ -1, uid) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
|||||||
@@ -428,4 +428,28 @@ public interface PermissionManagerServiceInternal extends PermissionManagerInter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the provider of the currently active HotwordDetectionService.
|
||||||
|
*
|
||||||
|
* @see HotwordDetectionServiceProvider
|
||||||
|
*/
|
||||||
|
void setHotwordDetectionServiceProvider(@Nullable HotwordDetectionServiceProvider provider);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the provider of the currently active HotwordDetectionService.
|
||||||
|
*
|
||||||
|
* @see HotwordDetectionServiceProvider
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
HotwordDetectionServiceProvider getHotwordDetectionServiceProvider();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the uid of the currently active
|
||||||
|
* {@link android.service.voice.HotwordDetectionService}, which should be granted RECORD_AUDIO
|
||||||
|
* and CAPTURE_AUDIO_HOTWORD permissions.
|
||||||
|
*/
|
||||||
|
interface HotwordDetectionServiceProvider {
|
||||||
|
int getUid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,10 @@ import android.content.pm.ResolveInfo;
|
|||||||
import android.location.LocationManagerInternal;
|
import android.location.LocationManagerInternal;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.Process;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
import android.service.voice.VoiceInteractionManagerInternal;
|
||||||
|
import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
@@ -78,6 +81,9 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final RoleManager mRoleManager;
|
private final RoleManager mRoleManager;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final VoiceInteractionManagerInternal mVoiceInteractionManagerInternal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The locking policy around the location tags is a bit special. Since we want to
|
* The locking policy around the location tags is a bit special. Since we want to
|
||||||
* avoid grabbing the lock on every op note we are taking the approach where the
|
* avoid grabbing the lock on every op note we are taking the approach where the
|
||||||
@@ -101,6 +107,8 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
|
|||||||
public AppOpsPolicy(@NonNull Context context) {
|
public AppOpsPolicy(@NonNull Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mRoleManager = mContext.getSystemService(RoleManager.class);
|
mRoleManager = mContext.getSystemService(RoleManager.class);
|
||||||
|
mVoiceInteractionManagerInternal = LocalServices.getService(
|
||||||
|
VoiceInteractionManagerInternal.class);
|
||||||
|
|
||||||
final LocationManagerInternal locationManagerInternal = LocalServices.getService(
|
final LocationManagerInternal locationManagerInternal = LocalServices.getService(
|
||||||
LocationManagerInternal.class);
|
LocationManagerInternal.class);
|
||||||
@@ -150,7 +158,7 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
|
|||||||
public int checkOperation(int code, int uid, String packageName,
|
public int checkOperation(int code, int uid, String packageName,
|
||||||
@Nullable String attributionTag, boolean raw,
|
@Nullable String attributionTag, boolean raw,
|
||||||
QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl) {
|
QuintFunction<Integer, Integer, String, String, Boolean, Integer> superImpl) {
|
||||||
return superImpl.apply(code, uid, packageName, attributionTag, raw);
|
return superImpl.apply(code, resolveUid(code, uid), packageName, attributionTag, raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -164,8 +172,8 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
|
|||||||
@Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, @Nullable
|
@Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, @Nullable
|
||||||
String message, boolean shouldCollectMessage, @NonNull HeptFunction<Integer, Integer,
|
String message, boolean shouldCollectMessage, @NonNull HeptFunction<Integer, Integer,
|
||||||
String, String, Boolean, String, Boolean, SyncNotedAppOp> superImpl) {
|
String, String, Boolean, String, Boolean, SyncNotedAppOp> superImpl) {
|
||||||
return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag), uid,
|
return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag),
|
||||||
packageName, attributionTag, shouldCollectAsyncNotedOp,
|
resolveUid(code, uid), packageName, attributionTag, shouldCollectAsyncNotedOp,
|
||||||
message, shouldCollectMessage);
|
message, shouldCollectMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,8 +198,9 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
|
|||||||
String, Boolean, Boolean, String, Boolean, Integer, Integer,
|
String, Boolean, Boolean, String, Boolean, Integer, Integer,
|
||||||
SyncNotedAppOp> superImpl) {
|
SyncNotedAppOp> superImpl) {
|
||||||
return superImpl.apply(token, resolveDatasourceOp(code, uid, packageName, attributionTag),
|
return superImpl.apply(token, resolveDatasourceOp(code, uid, packageName, attributionTag),
|
||||||
uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp,
|
resolveUid(code, uid), packageName, attributionTag, startIfModeDefault,
|
||||||
message, shouldCollectMessage, attributionFlags, attributionChainId);
|
shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags,
|
||||||
|
attributionChainId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -404,4 +413,23 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
|
|||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int resolveUid(int code, int uid) {
|
||||||
|
// The HotwordDetectionService is an isolated service, which ordinarily cannot hold
|
||||||
|
// permissions. So we allow it to assume the owning package identity for certain
|
||||||
|
// operations.
|
||||||
|
// Note: The package name coming from the audio server is already the one for the owning
|
||||||
|
// package, so we don't need to modify it.
|
||||||
|
if (Process.isIsolated(uid) // simple check which fails-fast for the common case
|
||||||
|
&& (code == AppOpsManager.OP_RECORD_AUDIO
|
||||||
|
|| code == AppOpsManager.OP_RECORD_AUDIO_HOTWORD)) {
|
||||||
|
final HotwordDetectionServiceIdentity hotwordDetectionServiceIdentity =
|
||||||
|
mVoiceInteractionManagerInternal.getHotwordDetectionServiceIdentity();
|
||||||
|
if (hotwordDetectionServiceIdentity != null
|
||||||
|
&& uid == hotwordDetectionServiceIdentity.getIsolatedUid()) {
|
||||||
|
uid = hotwordDetectionServiceIdentity.getOwnerUid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import android.media.AudioFormat;
|
|||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.AudioRecord;
|
import android.media.AudioRecord;
|
||||||
import android.media.MediaRecorder;
|
import android.media.MediaRecorder;
|
||||||
|
import android.os.Binder;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.IRemoteCallback;
|
import android.os.IRemoteCallback;
|
||||||
@@ -48,6 +49,7 @@ import android.service.voice.HotwordRejectedResult;
|
|||||||
import android.service.voice.IDspHotwordDetectionCallback;
|
import android.service.voice.IDspHotwordDetectionCallback;
|
||||||
import android.service.voice.IHotwordDetectionService;
|
import android.service.voice.IHotwordDetectionService;
|
||||||
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
|
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
|
||||||
|
import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.view.contentcapture.IContentCaptureManager;
|
import android.view.contentcapture.IContentCaptureManager;
|
||||||
@@ -56,6 +58,8 @@ import com.android.internal.annotations.GuardedBy;
|
|||||||
import com.android.internal.app.IHotwordRecognitionStatusCallback;
|
import com.android.internal.app.IHotwordRecognitionStatusCallback;
|
||||||
import com.android.internal.infra.AndroidFuture;
|
import com.android.internal.infra.AndroidFuture;
|
||||||
import com.android.internal.infra.ServiceConnector;
|
import com.android.internal.infra.ServiceConnector;
|
||||||
|
import com.android.server.LocalServices;
|
||||||
|
import com.android.server.pm.permission.PermissionManagerServiceInternal;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -94,20 +98,24 @@ final class HotwordDetectionConnection {
|
|||||||
private final AtomicBoolean mUpdateStateFinish = new AtomicBoolean(false);
|
private final AtomicBoolean mUpdateStateFinish = new AtomicBoolean(false);
|
||||||
|
|
||||||
final Object mLock;
|
final Object mLock;
|
||||||
|
final int mVoiceInteractionServiceUid;
|
||||||
final ComponentName mDetectionComponentName;
|
final ComponentName mDetectionComponentName;
|
||||||
final int mUser;
|
final int mUser;
|
||||||
final Context mContext;
|
final Context mContext;
|
||||||
final @NonNull ServiceConnector<IHotwordDetectionService> mRemoteHotwordDetectionService;
|
final @NonNull ServiceConnector<IHotwordDetectionService> mRemoteHotwordDetectionService;
|
||||||
boolean mBound;
|
boolean mBound;
|
||||||
|
volatile HotwordDetectionServiceIdentity mIdentity;
|
||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private ParcelFileDescriptor mCurrentAudioSink;
|
private ParcelFileDescriptor mCurrentAudioSink;
|
||||||
|
|
||||||
HotwordDetectionConnection(Object lock, Context context, ComponentName serviceName,
|
HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
|
||||||
int userId, boolean bindInstantServiceAllowed, @Nullable PersistableBundle options,
|
ComponentName serviceName, int userId, boolean bindInstantServiceAllowed,
|
||||||
@Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) {
|
@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory,
|
||||||
|
IHotwordRecognitionStatusCallback callback) {
|
||||||
mLock = lock;
|
mLock = lock;
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
mVoiceInteractionServiceUid = voiceInteractionServiceUid;
|
||||||
mDetectionComponentName = serviceName;
|
mDetectionComponentName = serviceName;
|
||||||
mUser = userId;
|
mUser = userId;
|
||||||
final Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE);
|
final Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE);
|
||||||
@@ -164,7 +172,15 @@ final class HotwordDetectionConnection {
|
|||||||
public void sendResult(Bundle bundle) throws RemoteException {
|
public void sendResult(Bundle bundle) throws RemoteException {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "updateState finish");
|
Slog.d(TAG, "updateState finish");
|
||||||
|
Slog.d(TAG, "updating hotword UID " + Binder.getCallingUid());
|
||||||
}
|
}
|
||||||
|
// TODO: Do this earlier than this callback and have the provider point to the
|
||||||
|
// current state stored in VoiceInteractionManagerServiceImpl.
|
||||||
|
final int uid = Binder.getCallingUid();
|
||||||
|
LocalServices.getService(PermissionManagerServiceInternal.class)
|
||||||
|
.setHotwordDetectionServiceProvider(() -> uid);
|
||||||
|
mIdentity =
|
||||||
|
new HotwordDetectionServiceIdentity(uid, mVoiceInteractionServiceUid);
|
||||||
future.complete(null);
|
future.complete(null);
|
||||||
try {
|
try {
|
||||||
if (mUpdateStateFinish.getAndSet(true)) {
|
if (mUpdateStateFinish.getAndSet(true)) {
|
||||||
@@ -235,6 +251,9 @@ final class HotwordDetectionConnection {
|
|||||||
if (mBound) {
|
if (mBound) {
|
||||||
mRemoteHotwordDetectionService.unbind();
|
mRemoteHotwordDetectionService.unbind();
|
||||||
mBound = false;
|
mBound = false;
|
||||||
|
LocalServices.getService(PermissionManagerServiceInternal.class)
|
||||||
|
.setHotwordDetectionServiceProvider(null);
|
||||||
|
mIdentity = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -251,6 +251,26 @@ public class VoiceInteractionManagerService extends SystemService {
|
|||||||
|
|
||||||
return TextUtils.equals(packageName, session.mSessionComponentName.getPackageName());
|
return TextUtils.equals(packageName, session.mSessionComponentName.getPackageName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HotwordDetectionServiceIdentity getHotwordDetectionServiceIdentity() {
|
||||||
|
// IMPORTANT: This is called when performing permission checks; do not lock!
|
||||||
|
|
||||||
|
// TODO: Have AppOpsPolicy register a listener instead of calling in here everytime.
|
||||||
|
// Then also remove the `volatile`s that were added with this method.
|
||||||
|
|
||||||
|
VoiceInteractionManagerServiceImpl impl =
|
||||||
|
VoiceInteractionManagerService.this.mServiceStub.mImpl;
|
||||||
|
if (impl == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
HotwordDetectionConnection hotwordDetectionConnection =
|
||||||
|
impl.mHotwordDetectionConnection;
|
||||||
|
if (hotwordDetectionConnection == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return hotwordDetectionConnection.mIdentity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// implementation entry point and binder service
|
// implementation entry point and binder service
|
||||||
@@ -258,7 +278,7 @@ public class VoiceInteractionManagerService extends SystemService {
|
|||||||
|
|
||||||
class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
|
class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
|
||||||
|
|
||||||
VoiceInteractionManagerServiceImpl mImpl;
|
volatile VoiceInteractionManagerServiceImpl mImpl;
|
||||||
|
|
||||||
private boolean mSafeMode;
|
private boolean mSafeMode;
|
||||||
private int mCurUser;
|
private int mCurUser;
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
|
|||||||
final ComponentName mHotwordDetectionComponentName;
|
final ComponentName mHotwordDetectionComponentName;
|
||||||
boolean mBound = false;
|
boolean mBound = false;
|
||||||
IVoiceInteractionService mService;
|
IVoiceInteractionService mService;
|
||||||
HotwordDetectionConnection mHotwordDetectionConnection;
|
volatile HotwordDetectionConnection mHotwordDetectionConnection;
|
||||||
|
|
||||||
VoiceInteractionSessionConnection mActiveSession;
|
VoiceInteractionSessionConnection mActiveSession;
|
||||||
int mDisabledShowContext;
|
int mDisabledShowContext;
|
||||||
@@ -447,8 +447,8 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
|
|||||||
|
|
||||||
if (mHotwordDetectionConnection == null) {
|
if (mHotwordDetectionConnection == null) {
|
||||||
mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
|
mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
|
||||||
mHotwordDetectionComponentName, mUser, /* bindInstantServiceAllowed= */ false,
|
mInfo.getServiceInfo().applicationInfo.uid, mHotwordDetectionComponentName,
|
||||||
options, sharedMemory, callback);
|
mUser, /* bindInstantServiceAllowed= */ false, options, sharedMemory, callback);
|
||||||
} else {
|
} else {
|
||||||
mHotwordDetectionConnection.updateStateLocked(options, sharedMemory);
|
mHotwordDetectionConnection.updateStateLocked(options, sharedMemory);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user