Add hotword detection metrics.
Bug: 207717787 Test: build & boot pass. Test: manual. Both trust and no-trust still work. Test: manual. In nornal case, log with expected values, see bug for details. Log expected value for some error cases (not all are tested) by local changes. Change-Id: Iaa778616eca4cfad83a94297d9cd6116bb9577e7
This commit is contained in:
@@ -23,6 +23,25 @@ import static android.service.voice.HotwordDetectionService.AUDIO_SOURCE_MICROPH
|
|||||||
import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_UNKNOWN;
|
import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_UNKNOWN;
|
||||||
import static android.service.voice.HotwordDetectionService.KEY_INITIALIZATION_STATUS;
|
import static android.service.voice.HotwordDetectionService.KEY_INITIALIZATION_STATUS;
|
||||||
|
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_ERROR;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_SUCCESS;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_NO_VALUE;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_OVER_MAX_CUSTOM_VALUE;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_TIMEOUT;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__AUDIO_SERVICE_DIED;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_UPDATE_STATE_AFTER_TIMEOUT;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__ON_CONNECTED;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE_FAIL;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_UPDATE_STATE;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED;
|
||||||
import static com.android.server.voiceinteraction.SoundTriggerSessionPermissionsDecorator.enforcePermissionForPreflight;
|
import static com.android.server.voiceinteraction.SoundTriggerSessionPermissionsDecorator.enforcePermissionForPreflight;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
@@ -92,13 +111,25 @@ final class HotwordDetectionConnection {
|
|||||||
static final boolean DEBUG = false;
|
static final boolean DEBUG = false;
|
||||||
|
|
||||||
// TODO: These constants need to be refined.
|
// TODO: These constants need to be refined.
|
||||||
private static final long VALIDATION_TIMEOUT_MILLIS = 3000;
|
private static final long VALIDATION_TIMEOUT_MILLIS = 4000;
|
||||||
private static final long MAX_UPDATE_TIMEOUT_MILLIS = 6000;
|
private static final long MAX_UPDATE_TIMEOUT_MILLIS = 6000;
|
||||||
private static final Duration MAX_UPDATE_TIMEOUT_DURATION =
|
private static final Duration MAX_UPDATE_TIMEOUT_DURATION =
|
||||||
Duration.ofMillis(MAX_UPDATE_TIMEOUT_MILLIS);
|
Duration.ofMillis(MAX_UPDATE_TIMEOUT_MILLIS);
|
||||||
private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
|
private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
|
||||||
private static final int MAX_ISOLATED_PROCESS_NUMBER = 10;
|
private static final int MAX_ISOLATED_PROCESS_NUMBER = 10;
|
||||||
|
|
||||||
|
// Hotword metrics
|
||||||
|
private static final int METRICS_INIT_UNKNOWN_TIMEOUT =
|
||||||
|
HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_TIMEOUT;
|
||||||
|
private static final int METRICS_INIT_UNKNOWN_NO_VALUE =
|
||||||
|
HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_NO_VALUE;
|
||||||
|
private static final int METRICS_INIT_UNKNOWN_OVER_MAX_CUSTOM_VALUE =
|
||||||
|
HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_UNKNOWN_OVER_MAX_CUSTOM_VALUE;
|
||||||
|
private static final int METRICS_INIT_CALLBACK_STATE_ERROR =
|
||||||
|
HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_ERROR;
|
||||||
|
private static final int METRICS_INIT_CALLBACK_STATE_SUCCESS =
|
||||||
|
HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__RESULT__CALLBACK_INIT_STATE_SUCCESS;
|
||||||
|
|
||||||
private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool();
|
private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool();
|
||||||
// TODO: This may need to be a Handler(looper)
|
// TODO: This may need to be a Handler(looper)
|
||||||
private final ScheduledExecutorService mScheduledExecutorService =
|
private final ScheduledExecutorService mScheduledExecutorService =
|
||||||
@@ -107,17 +138,20 @@ final class HotwordDetectionConnection {
|
|||||||
private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied;
|
private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied;
|
||||||
private final @NonNull ServiceConnectionFactory mServiceConnectionFactory;
|
private final @NonNull ServiceConnectionFactory mServiceConnectionFactory;
|
||||||
private final IHotwordRecognitionStatusCallback mCallback;
|
private final IHotwordRecognitionStatusCallback mCallback;
|
||||||
|
private final int mDetectorType;
|
||||||
|
|
||||||
final Object mLock;
|
final Object mLock;
|
||||||
final int mVoiceInteractionServiceUid;
|
final int mVoiceInteractionServiceUid;
|
||||||
final ComponentName mDetectionComponentName;
|
final ComponentName mDetectionComponentName;
|
||||||
final int mUser;
|
final int mUser;
|
||||||
final Context mContext;
|
final Context mContext;
|
||||||
|
|
||||||
volatile HotwordDetectionServiceIdentity mIdentity;
|
volatile HotwordDetectionServiceIdentity mIdentity;
|
||||||
private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback;
|
private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback;
|
||||||
private Instant mLastRestartInstant;
|
private Instant mLastRestartInstant;
|
||||||
|
|
||||||
private ScheduledFuture<?> mCancellationTaskFuture;
|
private ScheduledFuture<?> mCancellationTaskFuture;
|
||||||
|
private ScheduledFuture<?> mCancellationKeyPhraseDetectionFuture;
|
||||||
private ScheduledFuture<?> mDebugHotwordLoggingTimeoutFuture = null;
|
private ScheduledFuture<?> mDebugHotwordLoggingTimeoutFuture = null;
|
||||||
|
|
||||||
/** Identity used for attributing app ops when delivering data to the Interactor. */
|
/** Identity used for attributing app ops when delivering data to the Interactor. */
|
||||||
@@ -133,7 +167,6 @@ final class HotwordDetectionConnection {
|
|||||||
private @NonNull ServiceConnection mRemoteHotwordDetectionService;
|
private @NonNull ServiceConnection mRemoteHotwordDetectionService;
|
||||||
private IBinder mAudioFlinger;
|
private IBinder mAudioFlinger;
|
||||||
private boolean mDebugHotwordLogging = false;
|
private boolean mDebugHotwordLogging = false;
|
||||||
private final int mDetectorType;
|
|
||||||
|
|
||||||
HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
|
HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
|
||||||
Identity voiceInteractorIdentity, ComponentName serviceName, int userId,
|
Identity voiceInteractorIdentity, ComponentName serviceName, int userId,
|
||||||
@@ -169,6 +202,8 @@ final class HotwordDetectionConnection {
|
|||||||
Slog.v(TAG, "Time to restart the process, TTL has passed");
|
Slog.v(TAG, "Time to restart the process, TTL has passed");
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
restartProcessLocked();
|
restartProcessLocked();
|
||||||
|
HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType,
|
||||||
|
HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE);
|
||||||
}
|
}
|
||||||
}, 30, 30, TimeUnit.MINUTES);
|
}, 30, 30, TimeUnit.MINUTES);
|
||||||
}
|
}
|
||||||
@@ -201,6 +236,8 @@ final class HotwordDetectionConnection {
|
|||||||
// We restart the process instead of simply sending over the new binder, to avoid race
|
// We restart the process instead of simply sending over the new binder, to avoid race
|
||||||
// conditions with audio reading in the service.
|
// conditions with audio reading in the service.
|
||||||
restartProcessLocked();
|
restartProcessLocked();
|
||||||
|
HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType,
|
||||||
|
HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__AUDIO_SERVICE_DIED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,26 +257,32 @@ final class HotwordDetectionConnection {
|
|||||||
future.complete(null);
|
future.complete(null);
|
||||||
if (mUpdateStateAfterStartFinished.getAndSet(true)) {
|
if (mUpdateStateAfterStartFinished.getAndSet(true)) {
|
||||||
Slog.w(TAG, "call callback after timeout");
|
Slog.w(TAG, "call callback after timeout");
|
||||||
|
HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_EVENTS__EVENT__CALLBACK_UPDATE_STATE_AFTER_TIMEOUT,
|
||||||
|
mVoiceInteractionServiceUid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int status = bundle != null ? bundle.getInt(
|
Pair<Integer, Integer> statusResultPair = getInitStatusAndMetricsResult(bundle);
|
||||||
KEY_INITIALIZATION_STATUS,
|
int status = statusResultPair.first;
|
||||||
INITIALIZATION_STATUS_UNKNOWN)
|
int initResultMetricsResult = statusResultPair.second;
|
||||||
: INITIALIZATION_STATUS_UNKNOWN;
|
|
||||||
// Add the protection to avoid unexpected status
|
|
||||||
if (status > HotwordDetectionService.getMaxCustomInitializationStatus()
|
|
||||||
&& status != INITIALIZATION_STATUS_UNKNOWN) {
|
|
||||||
status = INITIALIZATION_STATUS_UNKNOWN;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
mCallback.onStatusReported(status);
|
mCallback.onStatusReported(status);
|
||||||
|
HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
|
||||||
|
initResultMetricsResult);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
|
// TODO: Add a new atom for RemoteException case, the error doesn't very
|
||||||
|
// correct here
|
||||||
Slog.w(TAG, "Failed to report initialization status: " + e);
|
Slog.w(TAG, "Failed to report initialization status: " + e);
|
||||||
|
HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
|
||||||
|
METRICS_INIT_CALLBACK_STATE_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
service.updateState(options, sharedMemory, statusCallback);
|
service.updateState(options, sharedMemory, statusCallback);
|
||||||
|
HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_UPDATE_STATE,
|
||||||
|
mVoiceInteractionServiceUid);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// TODO: (b/181842909) Report an error to voice interactor
|
// TODO: (b/181842909) Report an error to voice interactor
|
||||||
Slog.w(TAG, "Failed to updateState for HotwordDetectionService", e);
|
Slog.w(TAG, "Failed to updateState for HotwordDetectionService", e);
|
||||||
@@ -254,8 +297,12 @@ final class HotwordDetectionConnection {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
mCallback.onStatusReported(INITIALIZATION_STATUS_UNKNOWN);
|
mCallback.onStatusReported(INITIALIZATION_STATUS_UNKNOWN);
|
||||||
|
HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
|
||||||
|
METRICS_INIT_UNKNOWN_TIMEOUT);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.w(TAG, "Failed to report initialization status UNKNOWN", e);
|
Slog.w(TAG, "Failed to report initialization status UNKNOWN", e);
|
||||||
|
HotwordMetricsLogger.writeServiceInitResultEvent(mDetectorType,
|
||||||
|
METRICS_INIT_CALLBACK_STATE_ERROR);
|
||||||
}
|
}
|
||||||
} else if (err != null) {
|
} else if (err != null) {
|
||||||
Slog.w(TAG, "Failed to update state: " + err);
|
Slog.w(TAG, "Failed to update state: " + err);
|
||||||
@@ -265,6 +312,23 @@ final class HotwordDetectionConnection {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Pair<Integer, Integer> getInitStatusAndMetricsResult(Bundle bundle) {
|
||||||
|
if (bundle == null) {
|
||||||
|
return new Pair<>(INITIALIZATION_STATUS_UNKNOWN, METRICS_INIT_UNKNOWN_NO_VALUE);
|
||||||
|
}
|
||||||
|
int status = bundle.getInt(KEY_INITIALIZATION_STATUS, INITIALIZATION_STATUS_UNKNOWN);
|
||||||
|
if (status > HotwordDetectionService.getMaxCustomInitializationStatus()
|
||||||
|
&& status != INITIALIZATION_STATUS_UNKNOWN) {
|
||||||
|
return new Pair<>(INITIALIZATION_STATUS_UNKNOWN,
|
||||||
|
METRICS_INIT_UNKNOWN_OVER_MAX_CUSTOM_VALUE);
|
||||||
|
}
|
||||||
|
// TODO: should guard against negative here
|
||||||
|
int metricsResult = status == INITIALIZATION_STATUS_UNKNOWN
|
||||||
|
? METRICS_INIT_CALLBACK_STATE_ERROR
|
||||||
|
: METRICS_INIT_CALLBACK_STATE_SUCCESS;
|
||||||
|
return new Pair<>(status, metricsResult);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isBound() {
|
private boolean isBound() {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
return mRemoteHotwordDetectionService.isBound();
|
return mRemoteHotwordDetectionService.isBound();
|
||||||
@@ -481,12 +545,31 @@ final class HotwordDetectionConnection {
|
|||||||
Slog.d(TAG, "onDetected");
|
Slog.d(TAG, "onDetected");
|
||||||
}
|
}
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
|
// TODO: If the dsp trigger comes in after the timeout, we will log both events.
|
||||||
|
// Because we don't enforce the timeout yet. We should add some synchronizations
|
||||||
|
// within the runnable to prevent the race condition to log both events.
|
||||||
|
if (mCancellationKeyPhraseDetectionFuture != null) {
|
||||||
|
mCancellationKeyPhraseDetectionFuture.cancel(true);
|
||||||
|
}
|
||||||
|
HotwordMetricsLogger.writeKeyphraseTriggerEvent(
|
||||||
|
mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECTED);
|
||||||
if (!mValidatingDspTrigger) {
|
if (!mValidatingDspTrigger) {
|
||||||
Slog.i(TAG, "Ignoring #onDetected due to a process restart");
|
Slog.i(TAG, "Ignoring #onDetected due to a process restart");
|
||||||
|
HotwordMetricsLogger.writeKeyphraseTriggerEvent(
|
||||||
|
mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mValidatingDspTrigger = false;
|
mValidatingDspTrigger = false;
|
||||||
|
try {
|
||||||
enforcePermissionsForDataDelivery();
|
enforcePermissionsForDataDelivery();
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
HotwordMetricsLogger.writeKeyphraseTriggerEvent(
|
||||||
|
mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
externalCallback.onKeyphraseDetected(recognitionEvent, result);
|
externalCallback.onKeyphraseDetected(recognitionEvent, result);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
|
Slog.i(TAG, "Egressed " + HotwordDetectedResult.getUsageSize(result)
|
||||||
@@ -504,8 +587,17 @@ final class HotwordDetectionConnection {
|
|||||||
Slog.d(TAG, "onRejected");
|
Slog.d(TAG, "onRejected");
|
||||||
}
|
}
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
|
if (mCancellationKeyPhraseDetectionFuture != null) {
|
||||||
|
mCancellationKeyPhraseDetectionFuture.cancel(true);
|
||||||
|
}
|
||||||
|
HotwordMetricsLogger.writeKeyphraseTriggerEvent(
|
||||||
|
mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__REJECTED);
|
||||||
if (!mValidatingDspTrigger) {
|
if (!mValidatingDspTrigger) {
|
||||||
Slog.i(TAG, "Ignoring #onRejected due to a process restart");
|
Slog.i(TAG, "Ignoring #onRejected due to a process restart");
|
||||||
|
HotwordMetricsLogger.writeKeyphraseTriggerEvent(
|
||||||
|
mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_EXCEPTION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mValidatingDspTrigger = false;
|
mValidatingDspTrigger = false;
|
||||||
@@ -520,11 +612,20 @@ final class HotwordDetectionConnection {
|
|||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
mValidatingDspTrigger = true;
|
mValidatingDspTrigger = true;
|
||||||
mRemoteHotwordDetectionService.run(
|
mRemoteHotwordDetectionService.run(
|
||||||
service -> service.detectFromDspSource(
|
service -> {
|
||||||
|
// TODO: avoid allocate every time
|
||||||
|
mCancellationKeyPhraseDetectionFuture = mScheduledExecutorService.schedule(
|
||||||
|
() -> HotwordMetricsLogger
|
||||||
|
.writeKeyphraseTriggerEvent(mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__DETECT_TIMEOUT),
|
||||||
|
VALIDATION_TIMEOUT_MILLIS,
|
||||||
|
TimeUnit.MILLISECONDS);
|
||||||
|
service.detectFromDspSource(
|
||||||
recognitionEvent,
|
recognitionEvent,
|
||||||
recognitionEvent.getCaptureFormat(),
|
recognitionEvent.getCaptureFormat(),
|
||||||
VALIDATION_TIMEOUT_MILLIS,
|
VALIDATION_TIMEOUT_MILLIS,
|
||||||
internalCallback));
|
internalCallback);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,10 +726,16 @@ final class HotwordDetectionConnection {
|
|||||||
}
|
}
|
||||||
final boolean useHotwordDetectionService = mHotwordDetectionConnection != null;
|
final boolean useHotwordDetectionService = mHotwordDetectionConnection != null;
|
||||||
if (useHotwordDetectionService) {
|
if (useHotwordDetectionService) {
|
||||||
|
HotwordMetricsLogger.writeKeyphraseTriggerEvent(
|
||||||
|
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP,
|
||||||
|
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER);
|
||||||
mRecognitionEvent = recognitionEvent;
|
mRecognitionEvent = recognitionEvent;
|
||||||
mHotwordDetectionConnection.detectFromDspSource(
|
mHotwordDetectionConnection.detectFromDspSource(
|
||||||
recognitionEvent, mExternalCallback);
|
recognitionEvent, mExternalCallback);
|
||||||
} else {
|
} else {
|
||||||
|
HotwordMetricsLogger.writeKeyphraseTriggerEvent(
|
||||||
|
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR,
|
||||||
|
HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__RESULT__KEYPHRASE_TRIGGER);
|
||||||
mExternalCallback.onKeyphraseDetected(recognitionEvent, null);
|
mExternalCallback.onKeyphraseDetected(recognitionEvent, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -793,6 +900,7 @@ final class HotwordDetectionConnection {
|
|||||||
|
|
||||||
private boolean mRespectServiceConnectionStatusChanged = true;
|
private boolean mRespectServiceConnectionStatusChanged = true;
|
||||||
private boolean mIsBound = false;
|
private boolean mIsBound = false;
|
||||||
|
private boolean mIsLoggedFirstConnect = false;
|
||||||
|
|
||||||
ServiceConnection(@NonNull Context context,
|
ServiceConnection(@NonNull Context context,
|
||||||
@NonNull Intent intent, int bindingFlags, int userId,
|
@NonNull Intent intent, int bindingFlags, int userId,
|
||||||
@@ -816,6 +924,12 @@ final class HotwordDetectionConnection {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mIsBound = connected;
|
mIsBound = connected;
|
||||||
|
if (connected && !mIsLoggedFirstConnect) {
|
||||||
|
mIsLoggedFirstConnect = true;
|
||||||
|
HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_EVENTS__EVENT__ON_CONNECTED,
|
||||||
|
mVoiceInteractionServiceUid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,13 +960,25 @@ final class HotwordDetectionConnection {
|
|||||||
protected boolean bindService(
|
protected boolean bindService(
|
||||||
@NonNull android.content.ServiceConnection serviceConnection) {
|
@NonNull android.content.ServiceConnection serviceConnection) {
|
||||||
try {
|
try {
|
||||||
return mContext.bindIsolatedService(
|
HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE,
|
||||||
|
mVoiceInteractionServiceUid);
|
||||||
|
boolean bindResult = mContext.bindIsolatedService(
|
||||||
mIntent,
|
mIntent,
|
||||||
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE | mBindingFlags,
|
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE | mBindingFlags,
|
||||||
"hotword_detector_" + mInstanceNumber,
|
"hotword_detector_" + mInstanceNumber,
|
||||||
mExecutor,
|
mExecutor,
|
||||||
serviceConnection);
|
serviceConnection);
|
||||||
|
if (!bindResult) {
|
||||||
|
HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE_FAIL,
|
||||||
|
mVoiceInteractionServiceUid);
|
||||||
|
}
|
||||||
|
return bindResult;
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
|
HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
|
||||||
|
HOTWORD_DETECTOR_EVENTS__EVENT__REQUEST_BIND_SERVICE_FAIL,
|
||||||
|
mVoiceInteractionServiceUid);
|
||||||
Slog.wtf(TAG, "Can't bind to the hotword detection service!", e);
|
Slog.wtf(TAG, "Can't bind to the hotword detection service!", e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,24 @@
|
|||||||
|
|
||||||
package com.android.server.voiceinteraction;
|
package com.android.server.voiceinteraction;
|
||||||
|
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__NORMAL_DETECTOR;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__NORMAL_DETECTOR;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__NORMAL_DETECTOR;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
|
||||||
|
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
|
||||||
|
|
||||||
|
import android.service.voice.HotwordDetector;
|
||||||
|
|
||||||
import com.android.internal.util.FrameworkStatsLog;
|
import com.android.internal.util.FrameworkStatsLog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,6 +41,13 @@ import com.android.internal.util.FrameworkStatsLog;
|
|||||||
*/
|
*/
|
||||||
public final class HotwordMetricsLogger {
|
public final class HotwordMetricsLogger {
|
||||||
|
|
||||||
|
private static final int METRICS_INIT_DETECTOR_SOFTWARE =
|
||||||
|
HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
|
||||||
|
private static final int METRICS_INIT_DETECTOR_DSP =
|
||||||
|
HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
|
||||||
|
private static final int METRICS_INIT_NORMAL_DETECTOR =
|
||||||
|
HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR;
|
||||||
|
|
||||||
private HotwordMetricsLogger() {
|
private HotwordMetricsLogger() {
|
||||||
// Class only contains static utility functions, and should not be instantiated
|
// Class only contains static utility functions, and should not be instantiated
|
||||||
}
|
}
|
||||||
@@ -31,39 +56,99 @@ public final class HotwordMetricsLogger {
|
|||||||
* Logs information related to create hotword detector.
|
* Logs information related to create hotword detector.
|
||||||
*/
|
*/
|
||||||
public static void writeDetectorCreateEvent(int detectorType, boolean isCreated, int uid) {
|
public static void writeDetectorCreateEvent(int detectorType, boolean isCreated, int uid) {
|
||||||
FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED, detectorType,
|
int metricsDetectorType = getCreateMetricsDetectorType(detectorType);
|
||||||
isCreated, uid);
|
FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_CREATE_REQUESTED,
|
||||||
|
metricsDetectorType, isCreated, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs information related to hotword detection service init result.
|
* Logs information related to hotword detection service init result.
|
||||||
*/
|
*/
|
||||||
public static void writeServiceInitResultEvent(int detectorType, int result) {
|
public static void writeServiceInitResultEvent(int detectorType, int result) {
|
||||||
|
int metricsDetectorType = getInitMetricsDetectorType(detectorType);
|
||||||
FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED,
|
FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED,
|
||||||
detectorType, result);
|
metricsDetectorType, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs information related to hotword detection service restarting.
|
* Logs information related to hotword detection service restarting.
|
||||||
*/
|
*/
|
||||||
public static void writeServiceRestartEvent(int detectorType, int reason) {
|
public static void writeServiceRestartEvent(int detectorType, int reason) {
|
||||||
|
int metricsDetectorType = getRestartMetricsDetectorType(detectorType);
|
||||||
FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED,
|
FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_RESTARTED,
|
||||||
detectorType, reason);
|
metricsDetectorType, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs information related to keyphrase trigger.
|
* Logs information related to keyphrase trigger.
|
||||||
*/
|
*/
|
||||||
public static void writeKeyphraseTriggerEvent(int detectorType, int result) {
|
public static void writeKeyphraseTriggerEvent(int detectorType, int result) {
|
||||||
|
int metricsDetectorType = getKeyphraseMetricsDetectorType(detectorType);
|
||||||
FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED,
|
FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED,
|
||||||
detectorType, result);
|
metricsDetectorType, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs information related to hotword detector events.
|
* Logs information related to hotword detector events.
|
||||||
*/
|
*/
|
||||||
public static void writeDetectorEvent(int detectorType, int event, int uid) {
|
public static void writeDetectorEvent(int detectorType, int event, int uid) {
|
||||||
|
int metricsDetectorType = getDetectorMetricsDetectorType(detectorType);
|
||||||
FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS,
|
FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS,
|
||||||
detectorType, event, uid);
|
metricsDetectorType, event, uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getCreateMetricsDetectorType(int detectorType) {
|
||||||
|
switch (detectorType) {
|
||||||
|
case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
|
||||||
|
return HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
|
||||||
|
case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
|
||||||
|
return HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
|
||||||
|
default:
|
||||||
|
return HOTWORD_DETECTOR_CREATE_REQUESTED__DETECTOR_TYPE__NORMAL_DETECTOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getRestartMetricsDetectorType(int detectorType) {
|
||||||
|
switch (detectorType) {
|
||||||
|
case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
|
||||||
|
return HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
|
||||||
|
case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
|
||||||
|
return HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
|
||||||
|
default:
|
||||||
|
return HOTWORD_DETECTION_SERVICE_RESTARTED__DETECTOR_TYPE__NORMAL_DETECTOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getInitMetricsDetectorType(int detectorType) {
|
||||||
|
switch (detectorType) {
|
||||||
|
case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
|
||||||
|
return METRICS_INIT_DETECTOR_SOFTWARE;
|
||||||
|
case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
|
||||||
|
return METRICS_INIT_DETECTOR_DSP;
|
||||||
|
default:
|
||||||
|
return METRICS_INIT_NORMAL_DETECTOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getKeyphraseMetricsDetectorType(int detectorType) {
|
||||||
|
switch (detectorType) {
|
||||||
|
case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
|
||||||
|
return HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
|
||||||
|
case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
|
||||||
|
return HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
|
||||||
|
default:
|
||||||
|
return HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getDetectorMetricsDetectorType(int detectorType) {
|
||||||
|
switch (detectorType) {
|
||||||
|
case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
|
||||||
|
return HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
|
||||||
|
case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
|
||||||
|
return HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
|
||||||
|
default:
|
||||||
|
return HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__NORMAL_DETECTOR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -462,24 +462,33 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
|
|||||||
IHotwordRecognitionStatusCallback callback,
|
IHotwordRecognitionStatusCallback callback,
|
||||||
int detectorType) {
|
int detectorType) {
|
||||||
Slog.v(TAG, "updateStateLocked");
|
Slog.v(TAG, "updateStateLocked");
|
||||||
|
int voiceInteractionServiceUid = mInfo.getServiceInfo().applicationInfo.uid;
|
||||||
if (mHotwordDetectionComponentName == null) {
|
if (mHotwordDetectionComponentName == null) {
|
||||||
Slog.w(TAG, "Hotword detection service name not found");
|
Slog.w(TAG, "Hotword detection service name not found");
|
||||||
|
logDetectorCreateEventIfNeeded(callback, detectorType, false,
|
||||||
|
voiceInteractionServiceUid);
|
||||||
throw new IllegalStateException("Hotword detection service name not found");
|
throw new IllegalStateException("Hotword detection service name not found");
|
||||||
}
|
}
|
||||||
ServiceInfo hotwordDetectionServiceInfo = getServiceInfoLocked(
|
ServiceInfo hotwordDetectionServiceInfo = getServiceInfoLocked(
|
||||||
mHotwordDetectionComponentName, mUser);
|
mHotwordDetectionComponentName, mUser);
|
||||||
if (hotwordDetectionServiceInfo == null) {
|
if (hotwordDetectionServiceInfo == null) {
|
||||||
Slog.w(TAG, "Hotword detection service info not found");
|
Slog.w(TAG, "Hotword detection service info not found");
|
||||||
|
logDetectorCreateEventIfNeeded(callback, detectorType, false,
|
||||||
|
voiceInteractionServiceUid);
|
||||||
throw new IllegalStateException("Hotword detection service info not found");
|
throw new IllegalStateException("Hotword detection service info not found");
|
||||||
}
|
}
|
||||||
if (!isIsolatedProcessLocked(hotwordDetectionServiceInfo)) {
|
if (!isIsolatedProcessLocked(hotwordDetectionServiceInfo)) {
|
||||||
Slog.w(TAG, "Hotword detection service not in isolated process");
|
Slog.w(TAG, "Hotword detection service not in isolated process");
|
||||||
|
logDetectorCreateEventIfNeeded(callback, detectorType, false,
|
||||||
|
voiceInteractionServiceUid);
|
||||||
throw new IllegalStateException("Hotword detection service not in isolated process");
|
throw new IllegalStateException("Hotword detection service not in isolated process");
|
||||||
}
|
}
|
||||||
if (!Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(
|
if (!Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(
|
||||||
hotwordDetectionServiceInfo.permission)) {
|
hotwordDetectionServiceInfo.permission)) {
|
||||||
Slog.w(TAG, "Hotword detection service does not require permission "
|
Slog.w(TAG, "Hotword detection service does not require permission "
|
||||||
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
|
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
|
||||||
|
logDetectorCreateEventIfNeeded(callback, detectorType, false,
|
||||||
|
voiceInteractionServiceUid);
|
||||||
throw new SecurityException("Hotword detection service does not require permission "
|
throw new SecurityException("Hotword detection service does not require permission "
|
||||||
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
|
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
|
||||||
}
|
}
|
||||||
@@ -488,17 +497,23 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
|
|||||||
mInfo.getServiceInfo().packageName) == PackageManager.PERMISSION_GRANTED) {
|
mInfo.getServiceInfo().packageName) == PackageManager.PERMISSION_GRANTED) {
|
||||||
Slog.w(TAG, "Voice interaction service should not hold permission "
|
Slog.w(TAG, "Voice interaction service should not hold permission "
|
||||||
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
|
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
|
||||||
|
logDetectorCreateEventIfNeeded(callback, detectorType, false,
|
||||||
|
voiceInteractionServiceUid);
|
||||||
throw new SecurityException("Voice interaction service should not hold permission "
|
throw new SecurityException("Voice interaction service should not hold permission "
|
||||||
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
|
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sharedMemory != null && !sharedMemory.setProtect(OsConstants.PROT_READ)) {
|
if (sharedMemory != null && !sharedMemory.setProtect(OsConstants.PROT_READ)) {
|
||||||
Slog.w(TAG, "Can't set sharedMemory to be read-only");
|
Slog.w(TAG, "Can't set sharedMemory to be read-only");
|
||||||
|
logDetectorCreateEventIfNeeded(callback, detectorType, false,
|
||||||
|
voiceInteractionServiceUid);
|
||||||
throw new IllegalStateException("Can't set sharedMemory to be read-only");
|
throw new IllegalStateException("Can't set sharedMemory to be read-only");
|
||||||
}
|
}
|
||||||
|
|
||||||
mDetectorType = detectorType;
|
mDetectorType = detectorType;
|
||||||
|
|
||||||
|
logDetectorCreateEventIfNeeded(callback, detectorType, true,
|
||||||
|
voiceInteractionServiceUid);
|
||||||
if (mHotwordDetectionConnection == null) {
|
if (mHotwordDetectionConnection == null) {
|
||||||
mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
|
mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
|
||||||
mInfo.getServiceInfo().applicationInfo.uid, voiceInteractorIdentity,
|
mInfo.getServiceInfo().applicationInfo.uid, voiceInteractorIdentity,
|
||||||
@@ -509,6 +524,15 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void logDetectorCreateEventIfNeeded(IHotwordRecognitionStatusCallback callback,
|
||||||
|
int detectorType, boolean isCreated, int voiceInteractionServiceUid) {
|
||||||
|
if (callback != null) {
|
||||||
|
HotwordMetricsLogger.writeDetectorCreateEvent(detectorType, true,
|
||||||
|
voiceInteractionServiceUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void shutdownHotwordDetectionServiceLocked() {
|
public void shutdownHotwordDetectionServiceLocked() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "shutdownHotwordDetectionServiceLocked");
|
Slog.d(TAG, "shutdownHotwordDetectionServiceLocked");
|
||||||
|
|||||||
Reference in New Issue
Block a user