diff --git a/core/api/test-current.txt b/core/api/test-current.txt index e57493009ea0e..9b5e31ac67be3 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2093,6 +2093,14 @@ package android.media.tv.tuner { } +package android.media.voice { + + public final class KeyphraseModelManager { + method @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public void setModelDatabaseForTestEnabled(boolean); + } + +} + package android.net { public class NetworkPolicyManager { diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index 6b40d9873fbb5..24d5afc42d8ff 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -96,6 +96,21 @@ interface IVoiceInteractionManagerService { * @RequiresPermission Manifest.permission.MANAGE_VOICE_KEYPHRASES */ int deleteKeyphraseSoundModel(int keyphraseId, in String bcp47Locale); + + /** + * Override the persistent enrolled model database with an in-memory + * fake for testing purposes. + * + * @param enabled - {@code true} to enable the test database. {@code false} to enable + * the real, persistent database. + * @param token - IBinder used to register a death listener to clean-up the override + * if tests do not clean up gracefully. + */ + @EnforcePermission("MANAGE_VOICE_KEYPHRASES") + @JavaPassthrough(annotation= "@android.annotation.RequiresPermission(" + + "android.Manifest.permission.MANAGE_VOICE_KEYPHRASES)") + void setModelDatabaseForTestEnabled(boolean enabled, IBinder token); + /** * Indicates if there's a keyphrase sound model available for the given keyphrase ID and the * user ID of the caller. @@ -106,6 +121,7 @@ interface IVoiceInteractionManagerService { * @param bcp47Locale The BCP47 language tag for the keyphrase's locale. */ boolean isEnrolledForKeyphrase(int keyphraseId, String bcp47Locale); + /** * Generates KeyphraseMetadata for an enrolled sound model based on keyphrase string, locale, * and the user ID of the caller. diff --git a/media/java/android/media/voice/KeyphraseModelManager.java b/media/java/android/media/voice/KeyphraseModelManager.java index 8ec8967a353e6..5a690a57dbb29 100644 --- a/media/java/android/media/voice/KeyphraseModelManager.java +++ b/media/java/android/media/voice/KeyphraseModelManager.java @@ -21,7 +21,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.hardware.soundtrigger.SoundTrigger; +import android.os.Binder; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.util.Slog; @@ -154,4 +156,23 @@ public final class KeyphraseModelManager { throw e.rethrowFromSystemServer(); } } + + /** + * Override the persistent enrolled model database with an in-memory + * fake for testing purposes. + * + * @param enabled - {@code true} if the model enrollment database should be overridden with an + * in-memory fake. {@code false} if the real, persistent model enrollment database should be + * used. + * @hide + */ + @RequiresPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) + @TestApi + public void setModelDatabaseForTestEnabled(boolean enabled) { + try { + mVoiceInteractionManagerService.setModelDatabaseForTestEnabled(enabled, new Binder()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java index aaf7a9eacce67..5846ff699f69c 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java @@ -39,7 +39,7 @@ import java.util.UUID; * * @hide */ -public class DatabaseHelper extends SQLiteOpenHelper { +public class DatabaseHelper extends SQLiteOpenHelper implements IEnrolledModelDb { static final String TAG = "SoundModelDBHelper"; static final boolean DBG = false; @@ -153,11 +153,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } } - /** - * Updates the given keyphrase model, adds it, if it doesn't already exist. - * - * TODO: We only support one keyphrase currently. - */ + @Override public boolean updateKeyphraseSoundModel(KeyphraseSoundModel soundModel) { synchronized(this) { SQLiteDatabase db = getWritableDatabase(); @@ -193,9 +189,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } } - /** - * Deletes the sound model and associated keyphrases. - */ + @Override public boolean deleteKeyphraseSoundModel(int keyphraseId, int userHandle, String bcp47Locale) { // Normalize the locale to guard against SQL injection. bcp47Locale = Locale.forLanguageTag(bcp47Locale).toLanguageTag(); @@ -218,12 +212,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } } - /** - * Returns a matching {@link KeyphraseSoundModel} for the keyphrase ID. - * Returns null if a match isn't found. - * - * TODO: We only support one keyphrase currently. - */ + @Override public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, int userHandle, String bcp47Locale) { // Sanitize the locale to guard against SQL injection. @@ -237,12 +226,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { } } - /** - * Returns a matching {@link KeyphraseSoundModel} for the keyphrase string. - * Returns null if a match isn't found. - * - * TODO: We only support one keyphrase currently. - */ + @Override public KeyphraseSoundModel getKeyphraseSoundModel(String keyphrase, int userHandle, String bcp47Locale) { // Sanitize the locale to guard against SQL injection. diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/IEnrolledModelDb.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/IEnrolledModelDb.java new file mode 100644 index 0000000000000..f10c2f6a2325b --- /dev/null +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/IEnrolledModelDb.java @@ -0,0 +1,90 @@ +/** + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.voiceinteraction; + +import android.hardware.soundtrigger.SoundTrigger.Keyphrase; +import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; + +import java.io.PrintWriter; + +/** + * Interface for registering and querying the enrolled keyphrase model database for + * {@link VoiceInteractionManagerService}. + * This interface only supports one keyphrase per {@link KeyphraseSoundModel}. + * The non-update methods are uniquely keyed on fields of the first keyphrase + * {@link KeyphraseSoundModel#getKeyphrases()}. + * @hide + */ +public interface IEnrolledModelDb { + + //TODO(273286174): We only support one keyphrase currently. + /** + * Register the given {@link KeyphraseSoundModel}, or updates it if it already exists. + * + * @param soundModel - The sound model to register in the database. + * Updates the sound model if the keyphrase id, users, locale match an existing entry. + * Must have one and only one associated {@link Keyphrase}. + * @return - {@code true} if successful, {@code false} if unsuccessful + */ + boolean updateKeyphraseSoundModel(KeyphraseSoundModel soundModel); + + /** + * Deletes the previously registered keyphrase sound model from the database. + * + * @param keyphraseId - The (first) keyphrase ID of the KeyphraseSoundModel to delete. + * @param userHandle - The user handle making this request. Must be included in the user + * list of the registered sound model. + * @param bcp47Locale - The locale of the (first) keyphrase associated with this model. + * @return - {@code true} if successful, {@code false} if unsuccessful + */ + boolean deleteKeyphraseSoundModel(int keyphraseId, int userHandle, String bcp47Locale); + + //TODO(273286174): We only support one keyphrase currently. + /** + * Returns the first matching {@link KeyphraseSoundModel} for the keyphrase ID, locale pair, + * contingent on the userHandle existing in the user list for the model. + * Returns null if a match isn't found. + * + * @param keyphraseId - The (first) keyphrase ID of the KeyphraseSoundModel to query. + * @param userHandle - The user handle making this request. Must be included in the user + * list of the registered sound model. + * @param bcp47Locale - The locale of the (first) keyphrase associated with this model. + * @return - {@code true} if successful, {@code false} if unsuccessful + */ + KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, int userHandle, + String bcp47Locale); + + //TODO(273286174): We only support one keyphrase currently. + /** + * Returns the first matching {@link KeyphraseSoundModel} for the keyphrase ID, locale pair, + * contingent on the userHandle existing in the user list for the model. + * Returns null if a match isn't found. + * + * @param keyphrase - The text of (the first) keyphrase of the KeyphraseSoundModel to query. + * @param userHandle - The user handle making this request. Must be included in the user + * list of the registered sound model. + * @param bcp47Locale - The locale of the (first) keyphrase associated with this model. + * @return - {@code true} if successful, {@code false} if unsuccessful + */ + KeyphraseSoundModel getKeyphraseSoundModel(String keyphrase, int userHandle, + String bcp47Locale); + + /** + * Dumps contents of database for dumpsys + */ + void dump(PrintWriter pw); +} diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/TestModelEnrollmentDatabase.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/TestModelEnrollmentDatabase.java new file mode 100644 index 0000000000000..9bbaf8e25f954 --- /dev/null +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/TestModelEnrollmentDatabase.java @@ -0,0 +1,148 @@ +/** + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.voiceinteraction; + +import android.annotation.NonNull; +import android.hardware.soundtrigger.SoundTrigger.Keyphrase; +import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; + +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * In memory model enrollment database for testing purposes. + * @hide + */ +public class TestModelEnrollmentDatabase implements IEnrolledModelDb { + + // Record representing the primary key used in the real model database. + private static final class EnrollmentKey { + private final int mKeyphraseId; + private final List mUserIds; + private final String mLocale; + + EnrollmentKey(int keyphraseId, + @NonNull List userIds, @NonNull String locale) { + mKeyphraseId = keyphraseId; + mUserIds = Objects.requireNonNull(userIds); + mLocale = Objects.requireNonNull(locale); + } + + int keyphraseId() { + return mKeyphraseId; + } + + List userIds() { + return mUserIds; + } + + String locale() { + return mLocale; + } + + @Override + public String toString() { + StringJoiner sj = new StringJoiner(", ", "{", "}"); + sj.add("keyphraseId: " + mKeyphraseId); + sj.add("userIds: " + mUserIds.toString()); + sj.add("locale: " + mLocale.toString()); + return "EnrollmentKey: " + sj.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int res = 1; + res = prime * res + mKeyphraseId; + res = prime * res + mUserIds.hashCode(); + res = prime * res + mLocale.hashCode(); + return res; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + if (other == null) return false; + if (!(other instanceof EnrollmentKey)) return false; + EnrollmentKey that = (EnrollmentKey) other; + if (mKeyphraseId != that.mKeyphraseId) return false; + if (!mUserIds.equals(that.mUserIds)) return false; + if (!mLocale.equals(that.mLocale)) return false; + return true; + } + + } + + private final Map mModelMap = new HashMap<>(); + + @Override + public boolean updateKeyphraseSoundModel(KeyphraseSoundModel soundModel) { + final Keyphrase keyphrase = soundModel.getKeyphrases()[0]; + mModelMap.put(new EnrollmentKey(keyphrase.getId(), + Arrays.stream(keyphrase.getUsers()).boxed().toList(), + keyphrase.getLocale().toLanguageTag()), + soundModel); + return true; + } + + @Override + public boolean deleteKeyphraseSoundModel(int keyphraseId, int userHandle, String bcp47Locale) { + return mModelMap.keySet().removeIf(key -> (key.keyphraseId() == keyphraseId) + && key.locale().equals(bcp47Locale) + && key.userIds().contains(userHandle)); + } + + @Override + public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, int userHandle, + String bcp47Locale) { + return mModelMap.entrySet() + .stream() + .filter((entry) -> (entry.getKey().keyphraseId() == keyphraseId) + && entry.getKey().locale().equals(bcp47Locale) + && entry.getKey().userIds().contains(userHandle)) + .findFirst() + .map((entry) -> entry.getValue()) + .orElse(null); + } + + @Override + public KeyphraseSoundModel getKeyphraseSoundModel(String keyphrase, int userHandle, + String bcp47Locale) { + return mModelMap.entrySet() + .stream() + .filter((entry) -> (entry.getValue().getKeyphrases()[0].getText().equals(keyphrase) + && entry.getKey().locale().equals(bcp47Locale) + && entry.getKey().userIds().contains(userHandle))) + .findFirst() + .map((entry) -> entry.getValue()) + .orElse(null); + } + + + /** + * Dumps contents of database for dumpsys + */ + public void dump(PrintWriter pw) { + pw.println("Using test enrollment database, with enrolled models:"); + pw.println(mModelMap); + } +} diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index e1da2ca2a086c..dd0fa0ba6adfd 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -125,7 +125,9 @@ public class VoiceInteractionManagerService extends SystemService { final Context mContext; final ContentResolver mResolver; - final DatabaseHelper mDbHelper; + // Can be overridden for testing purposes + private IEnrolledModelDb mDbHelper; + private final IEnrolledModelDb mRealDbHelper; final ActivityManagerInternal mAmInternal; final ActivityTaskManagerInternal mAtmInternal; final UserManagerInternal mUserManagerInternal; @@ -143,7 +145,7 @@ public class VoiceInteractionManagerService extends SystemService { mResolver = context.getContentResolver(); mUserManagerInternal = Objects.requireNonNull( LocalServices.getService(UserManagerInternal.class)); - mDbHelper = new DatabaseHelper(context); + mDbHelper = mRealDbHelper = new DatabaseHelper(context); mServiceStub = new VoiceInteractionManagerServiceStub(); mAmInternal = Objects.requireNonNull( LocalServices.getService(ActivityManagerInternal.class)); @@ -1605,6 +1607,42 @@ public class VoiceInteractionManagerService extends SystemService { } } + @Override + @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_VOICE_KEYPHRASES) + public void setModelDatabaseForTestEnabled(boolean enabled, IBinder token) { + super.setModelDatabaseForTestEnabled_enforcePermission(); + enforceCallerAllowedToEnrollVoiceModel(); + synchronized (this) { + if (enabled) { + // Replace the dbhelper with a new test db + final var db = new TestModelEnrollmentDatabase(); + try { + // Listen to our caller death, and make sure we revert to the real + // db if they left the model in a test state. + token.linkToDeath(() -> { + synchronized (this) { + if (mDbHelper == db) { + mDbHelper = mRealDbHelper; + mImpl.notifySoundModelsChangedLocked(); + } + } + }, 0); + } catch (RemoteException e) { + // If the caller is already dead, nothing to do. + return; + } + mDbHelper = db; + mImpl.notifySoundModelsChangedLocked(); + } else { + // Nothing to do if the db is already set to the real impl. + if (mDbHelper != mRealDbHelper) { + mDbHelper = mRealDbHelper; + mImpl.notifySoundModelsChangedLocked(); + } + } + } + } + //----------------- SoundTrigger APIs --------------------------------// @Override public boolean isEnrolledForKeyphrase(int keyphraseId, String bcp47Locale) { @@ -1712,28 +1750,27 @@ public class VoiceInteractionManagerService extends SystemService { final long caller = Binder.clearCallingIdentity(); try { KeyphraseSoundModel soundModel = - mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUserId, bcp47Locale); + mDbHelper.getKeyphraseSoundModel(keyphraseId, + callingUserId, bcp47Locale); if (soundModel == null || soundModel.getUuid() == null || soundModel.getKeyphrases() == null) { Slog.w(TAG, "No matching sound model found in startRecognition"); return SoundTriggerInternal.STATUS_ERROR; - } else { - // Regardless of the status of the start recognition, we need to make sure - // that we unload this model if needed later. - synchronized (VoiceInteractionManagerServiceStub.this) { - mLoadedKeyphraseIds.put(keyphraseId, this); - if (mSessionExternalCallback == null - || mSessionInternalCallback == null - || callback.asBinder() != mSessionExternalCallback.asBinder()) { - mSessionInternalCallback = createSoundTriggerCallbackLocked( - callback); - mSessionExternalCallback = callback; - } - } - return mSession.startRecognition(keyphraseId, soundModel, - mSessionInternalCallback, recognitionConfig, runInBatterySaverMode); } + // Regardless of the status of the start recognition, we need to make sure + // that we unload this model if needed later. + synchronized (VoiceInteractionManagerServiceStub.this) { + mLoadedKeyphraseIds.put(keyphraseId, this); + if (mSessionExternalCallback == null + || mSessionInternalCallback == null + || callback.asBinder() != mSessionExternalCallback.asBinder()) { + mSessionInternalCallback = createSoundTriggerCallbackLocked(callback); + mSessionExternalCallback = callback; + } + } + return mSession.startRecognition(keyphraseId, soundModel, + mSessionInternalCallback, recognitionConfig, runInBatterySaverMode); } finally { Binder.restoreCallingIdentity(caller); } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index 62be2a555bc44..0ad86c11d29ae 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -71,7 +71,6 @@ import android.util.PrintWriterPrinter; import android.util.Slog; import android.view.IWindowManager; -import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IHotwordRecognitionStatusCallback; import com.android.internal.app.IVisualQueryDetectionAttentionListener; import com.android.internal.app.IVoiceActionCheckCallback; @@ -248,7 +247,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne Context.RECEIVER_EXPORTED); } - @GuardedBy("this") public void grantImplicitAccessLocked(int grantRecipientUid, @Nullable Intent intent) { final int grantRecipientAppId = UserHandle.getAppId(grantRecipientUid); final int grantRecipientUserId = UserHandle.getUserId(grantRecipientUid); @@ -258,7 +256,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne /* direct= */ true); } - @GuardedBy("this") public boolean showSessionLocked(@Nullable Bundle args, int flags, @Nullable String attributionTag, @Nullable IVoiceInteractionSessionShowCallback showCallback, @@ -331,7 +328,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public boolean hideSessionLocked() { if (mActiveSession != null) { return mActiveSession.hideLocked(); @@ -339,7 +335,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return false; } - @GuardedBy("this") public boolean deliverNewSessionLocked(IBinder token, IVoiceInteractionSession session, IVoiceInteractor interactor) { if (mActiveSession == null || token != mActiveSession.mToken) { @@ -350,7 +345,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return true; } - @GuardedBy("this") public int startVoiceActivityLocked(@Nullable String callingFeatureId, int callingPid, int callingUid, IBinder token, Intent intent, String resolvedType) { try { @@ -373,7 +367,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public int startAssistantActivityLocked(@Nullable String callingFeatureId, int callingPid, int callingUid, IBinder token, Intent intent, String resolvedType, @NonNull Bundle bundle) { @@ -397,7 +390,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void requestDirectActionsLocked(@NonNull IBinder token, int taskId, @NonNull IBinder assistToken, @Nullable RemoteCallback cancellationCallback, @NonNull RemoteCallback callback) { @@ -453,7 +445,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") void performDirectActionLocked(@NonNull IBinder token, @NonNull String actionId, @Nullable Bundle arguments, int taskId, IBinder assistToken, @Nullable RemoteCallback cancellationCallback, @@ -480,7 +471,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void setKeepAwakeLocked(IBinder token, boolean keepAwake) { try { if (mActiveSession == null || token != mActiveSession.mToken) { @@ -493,7 +483,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void closeSystemDialogsLocked(IBinder token) { try { if (mActiveSession == null || token != mActiveSession.mToken) { @@ -506,7 +495,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void finishLocked(IBinder token, boolean finishTask) { if (mActiveSession == null || (!finishTask && token != mActiveSession.mToken)) { Slog.w(TAG, "finish does not match active session"); @@ -516,7 +504,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession = null; } - @GuardedBy("this") public void setDisabledShowContextLocked(int callingUid, int flags) { int activeUid = mInfo.getServiceInfo().applicationInfo.uid; if (callingUid != activeUid) { @@ -526,7 +513,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mDisabledShowContext = flags; } - @GuardedBy("this") public int getDisabledShowContextLocked(int callingUid) { int activeUid = mInfo.getServiceInfo().applicationInfo.uid; if (callingUid != activeUid) { @@ -536,7 +522,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return mDisabledShowContext; } - @GuardedBy("this") public int getUserDisabledShowContextLocked(int callingUid) { int activeUid = mInfo.getServiceInfo().applicationInfo.uid; if (callingUid != activeUid) { @@ -550,7 +535,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return mInfo.getSupportsLocalInteraction(); } - @GuardedBy("this") public void startListeningVisibleActivityChangedLocked(@NonNull IBinder token) { if (DEBUG) { Slog.d(TAG, "startListeningVisibleActivityChangedLocked: token=" + token); @@ -563,7 +547,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession.startListeningVisibleActivityChangedLocked(); } - @GuardedBy("this") public void stopListeningVisibleActivityChangedLocked(@NonNull IBinder token) { if (DEBUG) { Slog.d(TAG, "stopListeningVisibleActivityChangedLocked: token=" + token); @@ -576,7 +559,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession.stopListeningVisibleActivityChangedLocked(); } - @GuardedBy("this") public void notifyActivityDestroyedLocked(@NonNull IBinder activityToken) { if (DEBUG) { Slog.d(TAG, "notifyActivityDestroyedLocked activityToken=" + activityToken); @@ -591,7 +573,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession.notifyActivityDestroyedLocked(activityToken); } - @GuardedBy("this") public void notifyActivityEventChangedLocked(@NonNull IBinder activityToken, int type) { if (DEBUG) { Slog.d(TAG, "notifyActivityEventChangedLocked type=" + type); @@ -606,7 +587,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession.notifyActivityEventChangedLocked(activityToken, type); } - @GuardedBy("this") public void updateStateLocked( @Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory, @@ -627,7 +607,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") private void verifyDetectorForHotwordDetectionLocked( @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback, @@ -685,7 +664,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne voiceInteractionServiceUid); } - @GuardedBy("this") private void verifyDetectorForVisualQueryDetectionLocked(@Nullable SharedMemory sharedMemory) { Slog.v(TAG, "verifyDetectorForVisualQueryDetectionLocked"); @@ -724,7 +702,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void initAndVerifyDetectorLocked( @NonNull Identity voiceInteractorIdentity, @Nullable PersistableBundle options, @@ -769,7 +746,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne detectorType); } - @GuardedBy("this") public void destroyDetectorLocked(IBinder token) { Slog.v(TAG, "destroyDetectorLocked"); @@ -788,7 +764,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") public void shutdownHotwordDetectionServiceLocked() { if (DEBUG) { Slog.d(TAG, "shutdownHotwordDetectionServiceLocked"); @@ -801,7 +776,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection = null; } - @GuardedBy("this") public void setVisualQueryDetectionAttentionListenerLocked( @Nullable IVisualQueryDetectionAttentionListener listener) { if (mHotwordDetectionConnection == null) { @@ -810,7 +784,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.setVisualQueryDetectionAttentionListenerLocked(listener); } - @GuardedBy("this") public void startPerceivingLocked(IVisualQueryDetectionVoiceInteractionCallback callback) { if (DEBUG) { Slog.d(TAG, "startPerceivingLocked"); @@ -824,7 +797,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.startPerceivingLocked(callback); } - @GuardedBy("this") public void stopPerceivingLocked() { if (DEBUG) { Slog.d(TAG, "stopPerceivingLocked"); @@ -838,7 +810,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.stopPerceivingLocked(); } - @GuardedBy("this") public void startListeningFromMicLocked( AudioFormat audioFormat, IMicrophoneHotwordDetectionVoiceInteractionCallback callback) { @@ -854,7 +825,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.startListeningFromMicLocked(audioFormat, callback); } - @GuardedBy("this") public void startListeningFromExternalSourceLocked( ParcelFileDescriptor audioStream, AudioFormat audioFormat, @@ -879,7 +849,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne options, token, callback); } - @GuardedBy("this") public void stopListeningFromMicLocked() { if (DEBUG) { Slog.d(TAG, "stopListeningFromMicLocked"); @@ -893,7 +862,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.stopListeningFromMicLocked(); } - @GuardedBy("this") public void triggerHardwareRecognitionEventForTestLocked( SoundTrigger.KeyphraseRecognitionEvent event, IHotwordRecognitionStatusCallback callback) { @@ -908,7 +876,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.triggerHardwareRecognitionEventForTestLocked(event, callback); } - @GuardedBy("this") public IRecognitionStatusCallback createSoundTriggerCallbackLocked( IHotwordRecognitionStatusCallback callback) { if (DEBUG) { @@ -933,12 +900,11 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne return null; } - @GuardedBy("this") boolean isIsolatedProcessLocked(@NonNull ServiceInfo serviceInfo) { return (serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0 && (serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) == 0; } - @GuardedBy("this") + boolean verifyProcessSharingLocked() { // only check this if both VQDS and HDS are declared in the app ServiceInfo hotwordInfo = getServiceInfoLocked(mHotwordDetectionComponentName, mUser); @@ -960,7 +926,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.forceRestart(); } - @GuardedBy("this") void setDebugHotwordLoggingLocked(boolean logging) { if (mHotwordDetectionConnection == null) { Slog.w(TAG, "Failed to set temporary debug logging: no hotword detection active"); @@ -969,7 +934,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection.setDebugHotwordLoggingLocked(logging); } - @GuardedBy("this") void resetHotwordDetectionConnectionLocked() { if (DEBUG) { Slog.d(TAG, "resetHotwordDetectionConnectionLocked"); @@ -984,7 +948,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mHotwordDetectionConnection = null; } - @GuardedBy("this") public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { if (!mValid) { pw.print(" NOT VALID: "); @@ -1023,7 +986,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") void startLocked() { Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); intent.setComponent(mComponent); @@ -1048,7 +1010,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") void shutdownLocked() { // If there is an active session, cancel it to allow it to clean up its window and other // state. @@ -1076,7 +1037,6 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne } } - @GuardedBy("this") void notifySoundModelsChangedLocked() { if (mService == null) { Slog.w(TAG, "Not bound to voice interaction service " + mComponent);