summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ahaan Ugale <augale@google.com> 2021-06-07 11:36:09 -0700
committer Ahaan Ugale <augale@google.com> 2021-06-08 14:26:04 -0700
commit5fc6910227c9052328002cedbf211ecb5edfcc4b (patch)
tree00a9edc26c3b3024dc9c1ea3ee8c0f7bef266ffa
parent1e70989c61e1e06c1de508cb8262299dd349ebd8 (diff)
Grant HotwordDetectionService RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD.
HotwordDetectionService is an isolated service which ordinarily cannot hold permissions. An isolated service has its own uid separate from the owning package. To allow it to access mic audio, we dynamically override the permissions check based on the currently bound HotwordDetectionService. Bug: 190011174 Test: manual - sample app can read audio (with a few other wip changes) Test: atest CtsVoiceInteractionTestCases Change-Id: I5abc809546184ef13cb9eb009f916afae6bdf1af
-rw-r--r--core/java/android/service/voice/VoiceInteractionManagerInternal.java37
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java92
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java24
-rw-r--r--services/core/java/com/android/server/policy/AppOpsPolicy.java38
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java25
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java22
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java6
7 files changed, 207 insertions, 37 deletions
diff --git a/core/java/android/service/voice/VoiceInteractionManagerInternal.java b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
index f5c959137d9b..c048286545c3 100644
--- a/core/java/android/service/voice/VoiceInteractionManagerInternal.java
+++ b/core/java/android/service/voice/VoiceInteractionManagerInternal.java
@@ -16,9 +16,12 @@
package android.service.voice;
+import android.annotation.Nullable;
import android.os.Bundle;
import android.os.IBinder;
+import com.android.internal.annotations.Immutable;
+
/**
* @hide
@@ -46,4 +49,38 @@ public abstract class VoiceInteractionManagerInternal {
* Returns whether the given package is currently in an active session
*/
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;
+ }
+ }
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index b0f8ee1925c5..cd78bf95c336 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -17,7 +17,9 @@
package com.android.server.pm.permission;
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.RECORD_AUDIO;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
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.parsing.PackageInfoUtils;
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.policy.PermissionPolicyInternal;
import com.android.server.policy.SoftRestrictedPermissionPolicy;
@@ -308,6 +311,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@NonNull
private final OnPermissionChangeListeners mOnPermissionChangeListeners;
+ @Nullable
+ private HotwordDetectionServiceProvider mHotwordDetectionServiceProvider;
+
// TODO: Take a look at the methods defined in the callback.
// 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
@@ -5200,6 +5206,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
public int[] getGidsForUid(int 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 AppOpsManager mAppOpsManager;
+ private final @NonNull PermissionManagerServiceInternal mPermissionManagerServiceInternal;
PermissionCheckerService(@NonNull Context context) {
mContext = context;
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+ mPermissionManagerServiceInternal =
+ LocalServices.getService(PermissionManagerServiceInternal.class);
}
@Override
@@ -5492,8 +5511,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
Objects.requireNonNull(attributionSourceState);
final AttributionSource attributionSource = new AttributionSource(
attributionSourceState);
- final int result = checkPermission(mContext, permission, attributionSource, message,
- forDataDelivery, startDataDelivery, fromDatasource, attributedOp);
+ final int result = checkPermission(mContext, mPermissionManagerServiceInternal,
+ permission, attributionSource, message, forDataDelivery, startDataDelivery,
+ fromDatasource, attributedOp);
// Finish any started op if some step in the attribution chain failed.
if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED) {
if (attributedOp == AppOpsManager.OP_NONE) {
@@ -5581,10 +5601,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@PermissionCheckerManager.PermissionResult
- private static int checkPermission(@NonNull Context context, @NonNull String permission,
- @NonNull AttributionSource attributionSource, @Nullable String message,
- boolean forDataDelivery, boolean startDataDelivery, boolean fromDatasource,
- int attributedOp) {
+ private static int checkPermission(@NonNull Context context,
+ @NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
+ @NonNull String permission, @NonNull AttributionSource attributionSource,
+ @Nullable String message, boolean forDataDelivery, boolean startDataDelivery,
+ boolean fromDatasource, int attributedOp) {
PermissionInfo permissionInfo = sPlatformPermissions.get(permission);
if (permissionInfo == null) {
@@ -5601,22 +5622,25 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
if (permissionInfo.isAppOp()) {
- return checkAppOpPermission(context, permission, attributionSource, message,
- forDataDelivery, fromDatasource);
+ return checkAppOpPermission(context, permissionManagerServiceInt, permission,
+ attributionSource, message, forDataDelivery, fromDatasource);
}
if (permissionInfo.isRuntime()) {
- return checkRuntimePermission(context, permission, attributionSource, message,
- forDataDelivery, startDataDelivery, fromDatasource, attributedOp);
+ return checkRuntimePermission(context, permissionManagerServiceInt, permission,
+ attributionSource, message, forDataDelivery, startDataDelivery,
+ fromDatasource, attributedOp);
}
- if (!fromDatasource && !checkPermission(context, permission, attributionSource.getUid(),
+ if (!fromDatasource && !checkPermission(context, permissionManagerServiceInt,
+ permission, attributionSource.getUid(),
attributionSource.getRenouncedPermissions())) {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
if (attributionSource.getNext() != null) {
- return checkPermission(context, permission, attributionSource.getNext(), message,
- forDataDelivery, startDataDelivery, /*fromDatasource*/ false, attributedOp);
+ return checkPermission(context, permissionManagerServiceInt, permission,
+ attributionSource.getNext(), message, forDataDelivery, startDataDelivery,
+ /*fromDatasource*/ false, attributedOp);
}
return PermissionChecker.PERMISSION_GRANTED;
@@ -5624,6 +5648,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@PermissionCheckerManager.PermissionResult
private static int checkAppOpPermission(@NonNull Context context,
+ @NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
@NonNull String permission, @NonNull AttributionSource attributionSource,
@Nullable String message, boolean forDataDelivery, boolean fromDatasource) {
final int op = AppOpsManager.permissionToOpCode(permission);
@@ -5667,13 +5692,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
case AppOpsManager.MODE_DEFAULT: {
- if (!skipCurrentChecks && !checkPermission(context, permission,
- attributionSource.getUid(), attributionSource
- .getRenouncedPermissions())) {
+ if (!skipCurrentChecks && !checkPermission(context,
+ permissionManagerServiceInt, permission, attributionSource.getUid(),
+ attributionSource.getRenouncedPermissions())) {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
- if (next != null && !checkPermission(context, permission,
- next.getUid(), next.getRenouncedPermissions())) {
+ if (next != null && !checkPermission(context, permissionManagerServiceInt,
+ permission, next.getUid(), next.getRenouncedPermissions())) {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
}
@@ -5688,6 +5713,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private static int checkRuntimePermission(@NonNull Context context,
+ @NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
@NonNull String permission, @NonNull AttributionSource attributionSource,
@Nullable String message, boolean forDataDelivery, boolean startDataDelivery,
boolean fromDatasource, int attributedOp) {
@@ -5712,13 +5738,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
// If we already checked the permission for this one, skip the work
- if (!skipCurrentChecks && !checkPermission(context, permission,
- current.getUid(), current.getRenouncedPermissions())) {
+ if (!skipCurrentChecks && !checkPermission(context, permissionManagerServiceInt,
+ permission, current.getUid(), current.getRenouncedPermissions())) {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
- if (next != null && !checkPermission(context, permission,
- next.getUid(), next.getRenouncedPermissions())) {
+ if (next != null && !checkPermission(context, permissionManagerServiceInt,
+ permission, next.getUid(), next.getRenouncedPermissions())) {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
@@ -5773,10 +5799,26 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- private static boolean checkPermission(@NonNull Context context, @NonNull String permission,
- int uid, @NonNull Set<String> renouncedPermissions) {
- final boolean permissionGranted = context.checkPermission(permission, /*pid*/ -1,
+ private static boolean checkPermission(@NonNull Context context,
+ @NonNull PermissionManagerServiceInternal permissionManagerServiceInt,
+ @NonNull String permission, int uid, @NonNull Set<String> renouncedPermissions) {
+ boolean permissionGranted = context.checkPermission(permission, /*pid*/ -1,
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)
&& context.checkPermission(Manifest.permission.RENOUNCE_PERMISSIONS,
/*pid*/ -1, uid) == PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 895cabc33bab..f4fb8102d922 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -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();
+ }
}
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index a6c93deb2d4d..d97648813753 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -33,7 +33,10 @@ import android.content.pm.ResolveInfo;
import android.location.LocationManagerInternal;
import android.net.Uri;
import android.os.IBinder;
+import android.os.Process;
import android.os.UserHandle;
+import android.service.voice.VoiceInteractionManagerInternal;
+import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -73,6 +76,9 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
@NonNull
private final RoleManager mRoleManager;
+ @NonNull
+ private final VoiceInteractionManagerInternal mVoiceInteractionManagerInternal;
+
/**
* 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
@@ -96,6 +102,8 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
public AppOpsPolicy(@NonNull Context context) {
mContext = context;
mRoleManager = mContext.getSystemService(RoleManager.class);
+ mVoiceInteractionManagerInternal = LocalServices.getService(
+ VoiceInteractionManagerInternal.class);
final LocationManagerInternal locationManagerInternal = LocalServices.getService(
LocationManagerInternal.class);
@@ -145,7 +153,7 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
public int checkOperation(int code, int uid, String packageName,
@Nullable String attributionTag, boolean raw,
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
@@ -159,8 +167,8 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
@Nullable String attributionTag, boolean shouldCollectAsyncNotedOp, @Nullable
String message, boolean shouldCollectMessage, @NonNull HeptFunction<Integer, Integer,
String, String, Boolean, String, Boolean, SyncNotedAppOp> superImpl) {
- return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag), uid,
- packageName, attributionTag, shouldCollectAsyncNotedOp,
+ return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag),
+ resolveUid(code, uid), packageName, attributionTag, shouldCollectAsyncNotedOp,
message, shouldCollectMessage);
}
@@ -185,8 +193,9 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
String, Boolean, Boolean, String, Boolean, Integer, Integer,
SyncNotedAppOp> superImpl) {
return superImpl.apply(token, resolveDatasourceOp(code, uid, packageName, attributionTag),
- uid, packageName, attributionTag, startIfModeDefault, shouldCollectAsyncNotedOp,
- message, shouldCollectMessage, attributionFlags, attributionChainId);
+ resolveUid(code, uid), packageName, attributionTag, startIfModeDefault,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags,
+ attributionChainId);
}
@Override
@@ -387,4 +396,23 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
}
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;
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 0bb09a9de07f..326d604e5dff 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -34,6 +34,7 @@ import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.MediaRecorder;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IRemoteCallback;
@@ -48,6 +49,7 @@ import android.service.voice.HotwordRejectedResult;
import android.service.voice.IDspHotwordDetectionCallback;
import android.service.voice.IHotwordDetectionService;
import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
+import android.service.voice.VoiceInteractionManagerInternal.HotwordDetectionServiceIdentity;
import android.util.Pair;
import android.util.Slog;
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.infra.AndroidFuture;
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.IOException;
@@ -94,20 +98,24 @@ final class HotwordDetectionConnection {
private final AtomicBoolean mUpdateStateFinish = new AtomicBoolean(false);
final Object mLock;
+ final int mVoiceInteractionServiceUid;
final ComponentName mDetectionComponentName;
final int mUser;
final Context mContext;
final @NonNull ServiceConnector<IHotwordDetectionService> mRemoteHotwordDetectionService;
boolean mBound;
+ volatile HotwordDetectionServiceIdentity mIdentity;
@GuardedBy("mLock")
private ParcelFileDescriptor mCurrentAudioSink;
- HotwordDetectionConnection(Object lock, Context context, ComponentName serviceName,
- int userId, boolean bindInstantServiceAllowed, @Nullable PersistableBundle options,
- @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) {
+ HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
+ ComponentName serviceName, int userId, boolean bindInstantServiceAllowed,
+ @Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory,
+ IHotwordRecognitionStatusCallback callback) {
mLock = lock;
mContext = context;
+ mVoiceInteractionServiceUid = voiceInteractionServiceUid;
mDetectionComponentName = serviceName;
mUser = userId;
final Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE);
@@ -153,7 +161,15 @@ final class HotwordDetectionConnection {
public void sendResult(Bundle bundle) throws RemoteException {
if (DEBUG) {
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);
try {
if (mUpdateStateFinish.getAndSet(true)) {
@@ -224,6 +240,9 @@ final class HotwordDetectionConnection {
if (mBound) {
mRemoteHotwordDetectionService.unbind();
mBound = false;
+ LocalServices.getService(PermissionManagerServiceInternal.class)
+ .setHotwordDetectionServiceProvider(null);
+ mIdentity = null;
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index f3d80b13f290..a14912e5593d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -251,6 +251,26 @@ public class VoiceInteractionManagerService extends SystemService {
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
@@ -258,7 +278,7 @@ public class VoiceInteractionManagerService extends SystemService {
class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
- VoiceInteractionManagerServiceImpl mImpl;
+ volatile VoiceInteractionManagerServiceImpl mImpl;
private boolean mSafeMode;
private int mCurUser;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 2206b0a61b9e..ca30bc51e046 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -98,7 +98,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
final ComponentName mHotwordDetectionComponentName;
boolean mBound = false;
IVoiceInteractionService mService;
- HotwordDetectionConnection mHotwordDetectionConnection;
+ volatile HotwordDetectionConnection mHotwordDetectionConnection;
VoiceInteractionSessionConnection mActiveSession;
int mDisabledShowContext;
@@ -447,8 +447,8 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
if (mHotwordDetectionConnection == null) {
mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
- mHotwordDetectionComponentName, mUser, /* bindInstantServiceAllowed= */ false,
- options, sharedMemory, callback);
+ mInfo.getServiceInfo().applicationInfo.uid, mHotwordDetectionComponentName,
+ mUser, /* bindInstantServiceAllowed= */ false, options, sharedMemory, callback);
} else {
mHotwordDetectionConnection.updateStateLocked(options, sharedMemory);
}