Merge "Implement passing the model data to the trusted process" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
98dfc2a69c
@@ -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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user