diff options
| author | TreeHugger Robot <treehugger-gerrit@google.com> | 2021-03-12 02:32:22 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2021-03-12 02:32:22 +0000 |
| commit | 98dfc2a69c6be90b46577c7968ea577beffff791 (patch) | |
| tree | 0761f416fa9d960c78c0db859cac5d119c71928e /core/java/android | |
| parent | d77d2bf6e45e4acc3013927fad5707c82dbcae9b (diff) | |
| parent | 9a75f1c529fce1bdbe54e698549590e9fa29ec4a (diff) | |
Merge "Implement passing the model data to the trusted process" into sc-dev
Diffstat (limited to 'core/java/android')
4 files changed, 149 insertions, 58 deletions
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index c1d9d5816c9d..def13db41559 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -41,10 +41,12 @@ import android.media.permission.Identity; import android.os.AsyncTask; import android.os.Binder; import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; +import android.os.SharedMemory; import android.util.Slog; import com.android.internal.app.IHotwordRecognitionStatusCallback; @@ -287,6 +289,7 @@ public class AlwaysOnHotwordDetector { private final Handler mHandler; private final IBinder mBinder = new Binder(); private final int mTargetSdkVersion; + private final boolean mSupportHotwordDetectionService; private int mAvailability = STATE_NOT_READY; @@ -488,11 +491,22 @@ public class AlwaysOnHotwordDetector { * @param callback A non-null Callback for receiving the recognition events. * @param modelManagementService A service that allows management of sound models. * @param targetSdkVersion The target SDK version. + * @param supportHotwordDetectionService {@code true} if hotword detection service should be + * triggered, otherwise {@code false}. + * @param options Application configuration data provided by the + * {@link VoiceInteractionService}. The system strips out any remotable objects or other + * contents that can be used to communicate with other processes. + * @param sharedMemory The unrestricted data blob provided by the + * {@link VoiceInteractionService}. Use this to provide the hotword models data or other + * such data to the trusted process. + * * @hide */ public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback, KeyphraseEnrollmentInfo keyphraseEnrollmentInfo, - IVoiceInteractionManagerService modelManagementService, int targetSdkVersion) { + IVoiceInteractionManagerService modelManagementService, int targetSdkVersion, + boolean supportHotwordDetectionService, @Nullable Bundle options, + @Nullable SharedMemory sharedMemory) { mText = text; mLocale = locale; mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo; @@ -501,6 +515,10 @@ public class AlwaysOnHotwordDetector { mInternalCallback = new SoundTriggerListener(mHandler); mModelManagementService = modelManagementService; mTargetSdkVersion = targetSdkVersion; + mSupportHotwordDetectionService = supportHotwordDetectionService; + if (mSupportHotwordDetectionService) { + setHotwordDetectionServiceConfig(options, sharedMemory); + } try { Identity identity = new Identity(); identity.packageName = ActivityThread.currentOpPackageName(); @@ -513,6 +531,38 @@ public class AlwaysOnHotwordDetector { } /** + * Set configuration and pass read-only data to hotword detection service. + * + * @param options Application configuration data provided by the + * {@link VoiceInteractionService}. The system strips out any remotable objects or other + * contents that can be used to communicate with other processes. + * @param sharedMemory The unrestricted data blob provided by the + * {@link VoiceInteractionService}. Use this to provide the hotword models data or other + * such data to the trusted process. + * + * @throws IllegalStateException if it doesn't support hotword detection service. + * + * @hide + */ + public final void setHotwordDetectionServiceConfig(@Nullable Bundle options, + @Nullable SharedMemory sharedMemory) { + if (DBG) { + Slog.d(TAG, "setHotwordDetectionServiceConfig()"); + } + if (!mSupportHotwordDetectionService) { + throw new IllegalStateException( + "setHotwordDetectionServiceConfig called, but it doesn't support hotword" + + " detection service"); + } + + try { + mModelManagementService.setHotwordDetectionServiceConfig(options, sharedMemory); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Gets the recognition modes supported by the associated keyphrase. * * @see #RECOGNITION_MODE_USER_IDENTIFICATION @@ -839,6 +889,14 @@ public class AlwaysOnHotwordDetector { synchronized (mLock) { mAvailability = STATE_INVALID; notifyStateChangedLocked(); + + if (mSupportHotwordDetectionService) { + try { + mModelManagementService.shutdownHotwordDetectionService(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } } diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java index 7f1c5ff96636..fcef26f13dd0 100644 --- a/core/java/android/service/voice/HotwordDetectionService.java +++ b/core/java/android/service/voice/HotwordDetectionService.java @@ -27,13 +27,17 @@ import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; import android.media.AudioFormat; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.SharedMemory; import android.util.Log; +import java.util.Locale; + /** * Implemented by an application that wants to offer detection for hotword. The system will * start the service after calling {@link VoiceInteractionService#setHotwordDetectionConfig}. @@ -76,6 +80,17 @@ public abstract class HotwordDetectionService extends Service { timeoutMillis, new DspHotwordDetectionCallback(callback))); } + + @Override + public void setConfig(Bundle options, SharedMemory sharedMemory) throws RemoteException { + if (DBG) { + Log.d(TAG, "#setConfig"); + } + mHandler.sendMessage(obtainMessage(HotwordDetectionService::onUpdateState, + HotwordDetectionService.this, + options, + sharedMemory)); + } }; @CallSuper @@ -121,6 +136,25 @@ public abstract class HotwordDetectionService extends Service { } /** + * Called when the {@link VoiceInteractionService#createAlwaysOnHotwordDetector(String, Locale, + * Bundle, SharedMemory, AlwaysOnHotwordDetector.Callback)} or {@link AlwaysOnHotwordDetector# + * setHotwordDetectionServiceConfig(Bundle, SharedMemory)} requests an update of the hotword + * detection parameters. + * + * @param options Application configuration data provided by the + * {@link VoiceInteractionService}. The system strips out any remotable objects or other + * contents that can be used to communicate with other processes. + * @param sharedMemory The unrestricted data blob provided by the + * {@link VoiceInteractionService}. Use this to provide the hotword models data or other + * such data to the trusted process. + * + * @hide + */ + @SystemApi + public void onUpdateState(@Nullable Bundle options, @Nullable SharedMemory sharedMemory) { + } + + /** * Callback for returning the detected result. * * @hide diff --git a/core/java/android/service/voice/IHotwordDetectionService.aidl b/core/java/android/service/voice/IHotwordDetectionService.aidl index cbe76e4bf69f..8f0874a5cb2e 100644 --- a/core/java/android/service/voice/IHotwordDetectionService.aidl +++ b/core/java/android/service/voice/IHotwordDetectionService.aidl @@ -17,7 +17,9 @@ package android.service.voice; import android.media.AudioFormat; +import android.os.Bundle; import android.os.ParcelFileDescriptor; +import android.os.SharedMemory; import android.service.voice.IDspHotwordDetectionCallback; /** @@ -31,4 +33,6 @@ oneway interface IHotwordDetectionService { in AudioFormat audioFormat, long timeoutMillis, in IDspHotwordDetectionCallback callback); + + void setConfig(in Bundle options, in SharedMemory sharedMemory); } diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 25f80900f1cf..048d9f57aded 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -17,7 +17,6 @@ package android.service.voice; import android.Manifest; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -36,6 +35,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SharedMemory; import android.provider.Settings; import android.util.ArraySet; import android.util.Log; @@ -47,8 +47,6 @@ import com.android.internal.util.function.pooled.PooledLambda; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -73,32 +71,6 @@ public class VoiceInteractionService extends Service { static final String TAG = VoiceInteractionService.class.getSimpleName(); /** - * Indicates that the given configs have been set successfully after calling - * {@link VoiceInteractionService#setHotwordDetectionConfig}. - * - * @hide - */ - @SystemApi - public static final int HOTWORD_CONFIG_SUCCESS = 0; - - /** - * Indicates that the given configs have been set unsuccessfully after calling - * {@link VoiceInteractionService#setHotwordDetectionConfig}. - * - * @hide - */ - @SystemApi - public static final int HOTWORD_CONFIG_FAILURE = 1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, prefix = { "HOTWORD_CONFIG_" }, value = { - HOTWORD_CONFIG_SUCCESS, - HOTWORD_CONFIG_FAILURE, - }) - public @interface HotwordConfigResult {} - - /** * The {@link Intent} that must be declared as handled by the service. * To be supported, the service must also require the * {@link android.Manifest.permission#BIND_VOICE_INTERACTION} permission so @@ -330,42 +302,51 @@ public class VoiceInteractionService extends Service { } /** - * Set hotword detection configuration. - * - * Note: Currently it will trigger hotword detection service after calling this function when - * all conditions meet the requirements. - * - * @param options Config data. - * @return {@link VoiceInteractionService#HOTWORD_CONFIG_SUCCESS} in case of success, - * {@link VoiceInteractionService#HOTWORD_CONFIG_FAILURE} in case of failure. + * Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale. + * This instance must be retained and used by the client. + * Calling this a second time invalidates the previously created hotword detector + * which can no longer be used to manage recognition. * - * @throws IllegalStateException if the function is called before onReady() is called. + * @param keyphrase The keyphrase that's being used, for example "Hello Android". + * @param locale The locale for which the enrollment needs to be performed. + * @param callback The callback to notify of detection events. + * @return An always-on hotword detector for the given keyphrase and locale. * * @hide */ @SystemApi - @HotwordConfigResult - public final int setHotwordDetectionConfig( - @SuppressLint("NullableCollection") @Nullable Bundle options) { - if (mSystemService == null) { - throw new IllegalStateException("Not available until onReady() is called"); - } - - try { - return mSystemService.setHotwordDetectionConfig(options); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + @NonNull + public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector( + @SuppressLint("MissingNullability") String keyphrase, // TODO: nullability properly + @SuppressLint({"MissingNullability", "UseIcu"}) Locale locale, + @SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) { + return createAlwaysOnHotwordDetectorInternal(keyphrase, locale, + /* supportHotwordDetectionService= */ false, /* options= */ null, + /* sharedMemory= */ null, callback); } /** - * Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale. - * This instance must be retained and used by the client. - * Calling this a second time invalidates the previously created hotword detector - * which can no longer be used to manage recognition. + * Create an {@link AlwaysOnHotwordDetector} and trigger a {@link HotwordDetectionService} + * service, then it will also pass the read-only data to hotword detection service. + * + * Like {@see #createAlwaysOnHotwordDetector(String, Locale, AlwaysOnHotwordDetector.Callback) + * }. Before calling this function, you should set a valid hotword detection service with + * android:hotwordDetectionService in an android.voice_interaction metadata file and set + * android:isolatedProcess="true" in the AndroidManifest.xml of hotword detection service. + * Otherwise it will throw IllegalStateException. After calling this function, the system will + * also trigger a hotword detection service and pass the read-only data back to it. + * + * <p>Note: The system will trigger hotword detection service after calling this function when + * all conditions meet the requirements. * * @param keyphrase The keyphrase that's being used, for example "Hello Android". * @param locale The locale for which the enrollment needs to be performed. + * @param options Application configuration data provided by the + * {@link VoiceInteractionService}. The system strips out any remotable objects or other + * contents that can be used to communicate with other processes. + * @param sharedMemory The unrestricted data blob provided by the + * {@link VoiceInteractionService}. Use this to provide the hotword models data or other + * such data to the trusted process. * @param callback The callback to notify of detection events. * @return An always-on hotword detector for the given keyphrase and locale. * @@ -374,8 +355,22 @@ public class VoiceInteractionService extends Service { @SystemApi @NonNull public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector( - @SuppressLint("MissingNullability") String keyphrase, // TODO: annotate nullability properly + @SuppressLint("MissingNullability") String keyphrase, // TODO: nullability properly + @SuppressLint({"MissingNullability", "UseIcu"}) Locale locale, + @Nullable Bundle options, + @Nullable SharedMemory sharedMemory, + @SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) { + return createAlwaysOnHotwordDetectorInternal(keyphrase, locale, + /* supportHotwordDetectionService= */ true, options, + sharedMemory, callback); + } + + private AlwaysOnHotwordDetector createAlwaysOnHotwordDetectorInternal( + @SuppressLint("MissingNullability") String keyphrase, // TODO: nullability properly @SuppressLint({"MissingNullability", "UseIcu"}) Locale locale, + boolean supportHotwordDetectionService, + @Nullable Bundle options, + @Nullable SharedMemory sharedMemory, @SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) { if (mSystemService == null) { throw new IllegalStateException("Not available until onReady() is called"); @@ -385,7 +380,8 @@ public class VoiceInteractionService extends Service { safelyShutdownHotwordDetector(); mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback, mKeyphraseEnrollmentInfo, mSystemService, - getApplicationContext().getApplicationInfo().targetSdkVersion); + getApplicationContext().getApplicationInfo().targetSdkVersion, + supportHotwordDetectionService, options, sharedMemory); } return mHotwordDetector; } @@ -432,7 +428,6 @@ public class VoiceInteractionService extends Service { } private void safelyShutdownHotwordDetector() { - // TODO (b/178171906): Need to check if the HotwordDetectionService should be unbound. synchronized (mLock) { if (mHotwordDetector == null) { return; |
