Merge "Implement passing the model data to the trusted process" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-03-12 02:32:22 +00:00
committed by Android (Google) Code Review
9 changed files with 249 additions and 87 deletions

View File

@@ -10251,6 +10251,7 @@ package android.service.voice {
ctor public HotwordDetectionService(); ctor public HotwordDetectionService();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public void onDetectFromDspSource(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.DspHotwordDetectionCallback); method public void onDetectFromDspSource(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.DspHotwordDetectionCallback);
method public void onUpdateState(@Nullable android.os.Bundle, @Nullable android.os.SharedMemory);
field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService"; field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService";
} }
@@ -10261,10 +10262,8 @@ package android.service.voice {
public class VoiceInteractionService extends android.app.Service { public class VoiceInteractionService extends android.app.Service {
method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback); method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, @Nullable android.os.Bundle, @Nullable android.os.SharedMemory, android.service.voice.AlwaysOnHotwordDetector.Callback);
method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager(); method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
method public final int setHotwordDetectionConfig(@Nullable android.os.Bundle);
field public static final int HOTWORD_CONFIG_FAILURE = 1; // 0x1
field public static final int HOTWORD_CONFIG_SUCCESS = 0; // 0x0
} }
} }

View File

@@ -41,10 +41,12 @@ import android.media.permission.Identity;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Binder; import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Message; import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SharedMemory;
import android.util.Slog; import android.util.Slog;
import com.android.internal.app.IHotwordRecognitionStatusCallback; import com.android.internal.app.IHotwordRecognitionStatusCallback;
@@ -287,6 +289,7 @@ public class AlwaysOnHotwordDetector {
private final Handler mHandler; private final Handler mHandler;
private final IBinder mBinder = new Binder(); private final IBinder mBinder = new Binder();
private final int mTargetSdkVersion; private final int mTargetSdkVersion;
private final boolean mSupportHotwordDetectionService;
private int mAvailability = STATE_NOT_READY; 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 callback A non-null Callback for receiving the recognition events.
* @param modelManagementService A service that allows management of sound models. * @param modelManagementService A service that allows management of sound models.
* @param targetSdkVersion The target SDK version. * @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 * @hide
*/ */
public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback, public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback,
KeyphraseEnrollmentInfo keyphraseEnrollmentInfo, KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
IVoiceInteractionManagerService modelManagementService, int targetSdkVersion) { IVoiceInteractionManagerService modelManagementService, int targetSdkVersion,
boolean supportHotwordDetectionService, @Nullable Bundle options,
@Nullable SharedMemory sharedMemory) {
mText = text; mText = text;
mLocale = locale; mLocale = locale;
mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo; mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo;
@@ -501,6 +515,10 @@ public class AlwaysOnHotwordDetector {
mInternalCallback = new SoundTriggerListener(mHandler); mInternalCallback = new SoundTriggerListener(mHandler);
mModelManagementService = modelManagementService; mModelManagementService = modelManagementService;
mTargetSdkVersion = targetSdkVersion; mTargetSdkVersion = targetSdkVersion;
mSupportHotwordDetectionService = supportHotwordDetectionService;
if (mSupportHotwordDetectionService) {
setHotwordDetectionServiceConfig(options, sharedMemory);
}
try { try {
Identity identity = new Identity(); Identity identity = new Identity();
identity.packageName = ActivityThread.currentOpPackageName(); identity.packageName = ActivityThread.currentOpPackageName();
@@ -512,6 +530,38 @@ public class AlwaysOnHotwordDetector {
new RefreshAvailabiltyTask().execute(); new RefreshAvailabiltyTask().execute();
} }
/**
* 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. * Gets the recognition modes supported by the associated keyphrase.
* *
@@ -839,6 +889,14 @@ public class AlwaysOnHotwordDetector {
synchronized (mLock) { synchronized (mLock) {
mAvailability = STATE_INVALID; mAvailability = STATE_INVALID;
notifyStateChangedLocked(); notifyStateChangedLocked();
if (mSupportHotwordDetectionService) {
try {
mModelManagementService.shutdownHotwordDetectionService();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
} }
} }

View File

@@ -27,13 +27,17 @@ import android.annotation.SystemApi;
import android.app.Service; import android.app.Service;
import android.content.Intent; import android.content.Intent;
import android.media.AudioFormat; import android.media.AudioFormat;
import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SharedMemory;
import android.util.Log; import android.util.Log;
import java.util.Locale;
/** /**
* Implemented by an application that wants to offer detection for hotword. The system will * Implemented by an application that wants to offer detection for hotword. The system will
* start the service after calling {@link VoiceInteractionService#setHotwordDetectionConfig}. * start the service after calling {@link VoiceInteractionService#setHotwordDetectionConfig}.
@@ -76,6 +80,17 @@ public abstract class HotwordDetectionService extends Service {
timeoutMillis, timeoutMillis,
new DspHotwordDetectionCallback(callback))); 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 @CallSuper
@@ -120,6 +135,25 @@ public abstract class HotwordDetectionService extends Service {
@NonNull DspHotwordDetectionCallback callback) { @NonNull DspHotwordDetectionCallback callback) {
} }
/**
* 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. * Callback for returning the detected result.
* *

View File

@@ -17,7 +17,9 @@
package android.service.voice; package android.service.voice;
import android.media.AudioFormat; import android.media.AudioFormat;
import android.os.Bundle;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.SharedMemory;
import android.service.voice.IDspHotwordDetectionCallback; import android.service.voice.IDspHotwordDetectionCallback;
/** /**
@@ -31,4 +33,6 @@ oneway interface IHotwordDetectionService {
in AudioFormat audioFormat, in AudioFormat audioFormat,
long timeoutMillis, long timeoutMillis,
in IDspHotwordDetectionCallback callback); in IDspHotwordDetectionCallback callback);
void setConfig(in Bundle options, in SharedMemory sharedMemory);
} }

View File

@@ -17,7 +17,6 @@
package android.service.voice; package android.service.voice;
import android.Manifest; import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
@@ -36,6 +35,7 @@ import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.SharedMemory;
import android.provider.Settings; import android.provider.Settings;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.Log; import android.util.Log;
@@ -47,8 +47,6 @@ import com.android.internal.util.function.pooled.PooledLambda;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -72,32 +70,6 @@ import java.util.Set;
public class VoiceInteractionService extends Service { public class VoiceInteractionService extends Service {
static final String TAG = VoiceInteractionService.class.getSimpleName(); 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. * The {@link Intent} that must be declared as handled by the service.
* To be supported, the service must also require the * To be supported, the service must also require the
@@ -329,35 +301,6 @@ 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.
*
* @throws IllegalStateException if the function is called before onReady() is called.
*
* @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();
}
}
/** /**
* Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale. * Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale.
* This instance must be retained and used by the client. * This instance must be retained and used by the client.
@@ -374,9 +317,61 @@ public class VoiceInteractionService extends Service {
@SystemApi @SystemApi
@NonNull @NonNull
public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector( public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(
@SuppressLint("MissingNullability") String keyphrase, // TODO: annotate nullability properly @SuppressLint("MissingNullability") String keyphrase, // TODO: nullability properly
@SuppressLint({"MissingNullability", "UseIcu"}) Locale locale, @SuppressLint({"MissingNullability", "UseIcu"}) Locale locale,
@SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) { @SuppressLint("MissingNullability") AlwaysOnHotwordDetector.Callback callback) {
return createAlwaysOnHotwordDetectorInternal(keyphrase, locale,
/* supportHotwordDetectionService= */ false, /* options= */ null,
/* sharedMemory= */ null, callback);
}
/**
* 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.
*
* @hide
*/
@SystemApi
@NonNull
public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(
@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) { if (mSystemService == null) {
throw new IllegalStateException("Not available until onReady() is called"); throw new IllegalStateException("Not available until onReady() is called");
} }
@@ -385,7 +380,8 @@ public class VoiceInteractionService extends Service {
safelyShutdownHotwordDetector(); safelyShutdownHotwordDetector();
mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback, mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
mKeyphraseEnrollmentInfo, mSystemService, mKeyphraseEnrollmentInfo, mSystemService,
getApplicationContext().getApplicationInfo().targetSdkVersion); getApplicationContext().getApplicationInfo().targetSdkVersion,
supportHotwordDetectionService, options, sharedMemory);
} }
return mHotwordDetector; return mHotwordDetector;
} }
@@ -432,7 +428,6 @@ public class VoiceInteractionService extends Service {
} }
private void safelyShutdownHotwordDetector() { private void safelyShutdownHotwordDetector() {
// TODO (b/178171906): Need to check if the HotwordDetectionService should be unbound.
synchronized (mLock) { synchronized (mLock) {
if (mHotwordDetector == null) { if (mHotwordDetector == null) {
return; return;

View File

@@ -21,6 +21,7 @@ import android.content.Intent;
import android.media.permission.Identity; import android.media.permission.Identity;
import android.os.Bundle; import android.os.Bundle;
import android.os.RemoteCallback; import android.os.RemoteCallback;
import android.os.SharedMemory;
import com.android.internal.app.IVoiceActionCheckCallback; import com.android.internal.app.IVoiceActionCheckCallback;
import com.android.internal.app.IVoiceInteractionSessionShowCallback; import com.android.internal.app.IVoiceInteractionSessionShowCallback;
@@ -225,14 +226,19 @@ interface IVoiceInteractionManagerService {
IBinder client); IBinder client);
/** /**
* Sets hotword detection configuration. * Set configuration and pass read-only data to hotword detection service.
* *
* Note: Currently it will trigger hotword detection service after calling this function when * @param options Application configuration data provided by the
* all conditions meet the requirements. * {@link VoiceInteractionService}. The system strips out any remotable objects or other
* * contents that can be used to communicate with other processes.
* @param options Config data. * @param sharedMemory The unrestricted data blob provided by the
* @return {@link VoiceInteractionService#HOTWORD_CONFIG_SUCCESS} in case of success, * {@link VoiceInteractionService}. Use this to provide the hotword models data or other
* {@link VoiceInteractionService#HOTWORD_CONFIG_FAILURE} in case of failure. * such data to the trusted process.
*/ */
int setHotwordDetectionConfig(in Bundle options); void setHotwordDetectionServiceConfig(in Bundle options, in SharedMemory sharedMemory);
/**
* Requests to shutdown hotword detection service.
*/
void shutdownHotwordDetectionService();
} }

View File

@@ -17,6 +17,7 @@
package com.android.server.voiceinteraction; package com.android.server.voiceinteraction;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -25,8 +26,10 @@ import android.hardware.soundtrigger.SoundTrigger;
import android.media.AudioAttributes; import android.media.AudioAttributes;
import android.media.AudioRecord; import android.media.AudioRecord;
import android.media.MediaRecorder; import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SharedMemory;
import android.service.voice.AlwaysOnHotwordDetector; import android.service.voice.AlwaysOnHotwordDetector;
import android.service.voice.HotwordDetectionService; import android.service.voice.HotwordDetectionService;
import android.service.voice.IDspHotwordDetectionCallback; import android.service.voice.IDspHotwordDetectionCallback;
@@ -74,7 +77,8 @@ final class HotwordDetectionConnection {
boolean mBound; boolean mBound;
HotwordDetectionConnection(Object lock, Context context, ComponentName serviceName, HotwordDetectionConnection(Object lock, Context context, ComponentName serviceName,
int userId, boolean bindInstantServiceAllowed) { int userId, boolean bindInstantServiceAllowed, @Nullable Bundle options,
@Nullable SharedMemory sharedMemory) {
mLock = lock; mLock = lock;
mContext = context; mContext = context;
mDetectionComponentName = serviceName; mDetectionComponentName = serviceName;
@@ -90,6 +94,14 @@ final class HotwordDetectionConnection {
boolean connected) { boolean connected) {
synchronized (mLock) { synchronized (mLock) {
mBound = connected; mBound = connected;
if (connected) {
try {
service.setConfig(options, sharedMemory);
} catch (RemoteException e) {
// TODO: (b/181842909) Report an error to voice interactor
Slog.w(TAG, "Failed to setConfig for HotwordDetectionService", e);
}
}
} }
} }
@@ -117,6 +129,11 @@ final class HotwordDetectionConnection {
} }
} }
void setConfigLocked(Bundle options, SharedMemory sharedMemory) {
mRemoteHotwordDetectionService.run(
service -> service.setConfig(options, sharedMemory));
}
private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent, private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
IHotwordRecognitionStatusCallback externalCallback) { IHotwordRecognitionStatusCallback externalCallback) {
if (DEBUG) { if (DEBUG) {

View File

@@ -60,6 +60,7 @@ import android.os.RemoteCallback;
import android.os.RemoteCallbackList; import android.os.RemoteCallbackList;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ResultReceiver; import android.os.ResultReceiver;
import android.os.SharedMemory;
import android.os.ShellCallback; import android.os.ShellCallback;
import android.os.Trace; import android.os.Trace;
import android.os.UserHandle; import android.os.UserHandle;
@@ -982,23 +983,46 @@ public class VoiceInteractionManagerService extends SystemService {
} }
@Override @Override
public int setHotwordDetectionConfig(Bundle options) { public void setHotwordDetectionServiceConfig(@Nullable Bundle options,
@Nullable SharedMemory sharedMemory) {
synchronized (this) { synchronized (this) {
enforceIsCurrentVoiceInteractionService(); enforceIsCurrentVoiceInteractionService();
if (mImpl == null) { if (mImpl == null) {
Slog.w(TAG, Slog.w(TAG,
"setHotwordDetectionConfig without running voice interaction service"); "setHotwordDetectionServiceConfig without running voice"
return VoiceInteractionService.HOTWORD_CONFIG_FAILURE; + " interaction service");
return;
} }
final long caller = Binder.clearCallingIdentity(); final long caller = Binder.clearCallingIdentity();
try { try {
return mImpl.setHotwordDetectionConfigLocked(options); mImpl.setHotwordDetectionServiceConfigLocked(options, sharedMemory);
} finally { } finally {
Binder.restoreCallingIdentity(caller); Binder.restoreCallingIdentity(caller);
} }
} }
} }
@Override
public void shutdownHotwordDetectionService() {
synchronized (this) {
enforceIsCurrentVoiceInteractionService();
if (mImpl == null) {
Slog.w(TAG,
"shutdownHotwordDetectionService without running voice"
+ " interaction service");
return;
}
final long caller = Binder.clearCallingIdentity();
try {
mImpl.shutdownHotwordDetectionServiceLocked();
} finally {
Binder.restoreCallingIdentity(caller);
}
}
}
//----------------- Model management APIs --------------------------------// //----------------- Model management APIs --------------------------------//
@Override @Override

View File

@@ -43,11 +43,13 @@ import android.os.IBinder;
import android.os.RemoteCallback; import android.os.RemoteCallback;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.SharedMemory;
import android.os.UserHandle; import android.os.UserHandle;
import android.service.voice.IVoiceInteractionService; import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession; import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionService; import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo; import android.service.voice.VoiceInteractionServiceInfo;
import android.system.OsConstants;
import android.util.PrintWriterPrinter; import android.util.PrintWriterPrinter;
import android.util.Slog; import android.util.Slog;
import android.view.IWindowManager; import android.view.IWindowManager;
@@ -389,25 +391,48 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
return mInfo.getSupportsLocalInteraction(); return mInfo.getSupportsLocalInteraction();
} }
public int setHotwordDetectionConfigLocked(Bundle options) { public void setHotwordDetectionServiceConfigLocked(@Nullable Bundle options,
@Nullable SharedMemory sharedMemory) {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "setHotwordDetectionConfigLocked"); Slog.d(TAG, "setHotwordDetectionServiceConfigLocked");
} }
if (mHotwordDetectionComponentName == null) { if (mHotwordDetectionComponentName == null) {
Slog.e(TAG, "Calling setHotwordDetectionConfigLocked, but hotword detection service" Slog.w(TAG, "Hotword detection service name not found");
+ " name not found"); throw new IllegalStateException("Hotword detection service name not found");
return VoiceInteractionService.HOTWORD_CONFIG_FAILURE;
} }
if (!isIsolatedProcessLocked(mHotwordDetectionComponentName)) { if (!isIsolatedProcessLocked(mHotwordDetectionComponentName)) {
return VoiceInteractionService.HOTWORD_CONFIG_FAILURE; Slog.w(TAG, "Hotword detection service not in isolated process");
throw new IllegalStateException("Hotword detection service not in isolated process");
} }
// TODO : Need to check related permissions for hotword detection service // TODO : Need to check related permissions for hotword detection service
// TODO : Sanitize for bundle // TODO : Sanitize for bundle
mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext, if (sharedMemory != null && !sharedMemory.setProtect(OsConstants.PROT_READ)) {
mHotwordDetectionComponentName, mUser, /* bindInstantServiceAllowed= */ false); Slog.w(TAG, "Can't set sharedMemory to be read-only");
throw new IllegalStateException("Can't set sharedMemory to be read-only");
}
return VoiceInteractionService.HOTWORD_CONFIG_SUCCESS; if (mHotwordDetectionConnection == null) {
mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
mHotwordDetectionComponentName, mUser, /* bindInstantServiceAllowed= */ false,
options, sharedMemory);
} else {
mHotwordDetectionConnection.setConfigLocked(options, sharedMemory);
}
}
public void shutdownHotwordDetectionServiceLocked() {
if (DEBUG) {
Slog.d(TAG, "shutdownHotwordDetectionServiceLocked");
}
if (mHotwordDetectionConnection == null) {
Slog.w(TAG, "shutdown, but no hotword detection connection");
return;
}
mHotwordDetectionConnection.cancelLocked();
mHotwordDetectionConnection = null;
} }
public IRecognitionStatusCallback createSoundTriggerCallbackLocked( public IRecognitionStatusCallback createSoundTriggerCallbackLocked(