• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.voiceinteraction;
18 
19 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
20 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
21 import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
22 import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
23 
24 import android.Manifest;
25 import android.annotation.CallbackExecutor;
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.annotation.RequiresPermission;
29 import android.annotation.UserIdInt;
30 import android.app.ActivityManager;
31 import android.app.ActivityManagerInternal;
32 import android.app.ActivityOptions;
33 import android.app.AppGlobals;
34 import android.app.admin.DevicePolicyManagerInternal;
35 import android.app.role.OnRoleHoldersChangedListener;
36 import android.app.role.RoleManager;
37 import android.content.ComponentName;
38 import android.content.ContentResolver;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.pm.ActivityInfo;
42 import android.content.pm.ApplicationInfo;
43 import android.content.pm.IPackageManager;
44 import android.content.pm.PackageManager;
45 import android.content.pm.ResolveInfo;
46 import android.content.pm.ServiceInfo;
47 import android.content.pm.ShortcutServiceInternal;
48 import android.content.pm.UserInfo;
49 import android.content.res.Resources;
50 import android.database.ContentObserver;
51 import android.graphics.Bitmap;
52 import android.hardware.soundtrigger.IRecognitionStatusCallback;
53 import android.hardware.soundtrigger.KeyphraseMetadata;
54 import android.hardware.soundtrigger.ModelParams;
55 import android.hardware.soundtrigger.SoundTrigger;
56 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
57 import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
58 import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
59 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
60 import android.media.AudioFormat;
61 import android.media.permission.Identity;
62 import android.media.permission.PermissionUtil;
63 import android.media.permission.SafeCloseable;
64 import android.os.Binder;
65 import android.os.Bundle;
66 import android.os.Handler;
67 import android.os.IBinder;
68 import android.os.Parcel;
69 import android.os.ParcelFileDescriptor;
70 import android.os.PersistableBundle;
71 import android.os.RemoteCallback;
72 import android.os.RemoteCallbackList;
73 import android.os.RemoteException;
74 import android.os.ResultReceiver;
75 import android.os.SharedMemory;
76 import android.os.ShellCallback;
77 import android.os.Trace;
78 import android.os.UserHandle;
79 import android.provider.Settings;
80 import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
81 import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
82 import android.service.voice.IVoiceInteractionSession;
83 import android.service.voice.VoiceInteractionManagerInternal;
84 import android.service.voice.VoiceInteractionManagerInternal.WearableHotwordDetectionCallback;
85 import android.service.voice.VoiceInteractionService;
86 import android.service.voice.VoiceInteractionServiceInfo;
87 import android.service.voice.VoiceInteractionSession;
88 import android.text.TextUtils;
89 import android.util.ArrayMap;
90 import android.util.ArraySet;
91 import android.util.Log;
92 import android.util.Slog;
93 import android.window.ScreenCapture;
94 
95 import com.android.internal.R;
96 import com.android.internal.annotations.GuardedBy;
97 import com.android.internal.app.IHotwordRecognitionStatusCallback;
98 import com.android.internal.app.IVisualQueryDetectionAttentionListener;
99 import com.android.internal.app.IVisualQueryRecognitionStatusListener;
100 import com.android.internal.app.IVoiceActionCheckCallback;
101 import com.android.internal.app.IVoiceInteractionAccessibilitySettingsListener;
102 import com.android.internal.app.IVoiceInteractionManagerService;
103 import com.android.internal.app.IVoiceInteractionSessionListener;
104 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
105 import com.android.internal.app.IVoiceInteractionSoundTriggerSession;
106 import com.android.internal.app.IVoiceInteractor;
107 import com.android.internal.content.PackageMonitor;
108 import com.android.internal.os.BackgroundThread;
109 import com.android.internal.util.DumpUtils;
110 import com.android.server.FgThread;
111 import com.android.server.LocalServices;
112 import com.android.server.SoundTriggerInternal;
113 import com.android.server.SystemService;
114 import com.android.server.UiThread;
115 import com.android.server.pm.UserManagerInternal;
116 import com.android.server.pm.permission.LegacyPermissionManagerInternal;
117 import com.android.server.policy.AppOpsPolicy;
118 import com.android.server.utils.Slogf;
119 import com.android.server.utils.TimingsTraceAndSlog;
120 import com.android.server.wm.ActivityAssistInfo;
121 import com.android.server.wm.ActivityTaskManagerInternal;
122 import com.android.server.wm.WindowManagerInternal;
123 
124 import java.io.FileDescriptor;
125 import java.io.PrintWriter;
126 import java.util.ArrayList;
127 import java.util.List;
128 import java.util.Locale;
129 import java.util.Objects;
130 import java.util.Set;
131 import java.util.concurrent.Executor;
132 
133 /**
134  * SystemService that publishes an IVoiceInteractionManagerService.
135  */
136 public class VoiceInteractionManagerService extends SystemService {
137     static final String TAG = "VoiceInteractionManager";
138     static final boolean DEBUG = false;
139 
140     /** Static constants used by Contextual Search helper. */
141     private static final String CS_KEY_FLAG_SECURE_FOUND =
142             "com.android.contextualsearch.flag_secure_found";
143     private static final String CS_KEY_FLAG_SCREENSHOT =
144             "com.android.contextualsearch.screenshot";
145     private static final String CS_KEY_FLAG_IS_MANAGED_PROFILE_VISIBLE =
146             "com.android.contextualsearch.is_managed_profile_visible";
147     private static final String CS_KEY_FLAG_VISIBLE_PACKAGE_NAMES =
148             "com.android.contextualsearch.visible_package_names";
149     private static final String CS_INTENT_FILTER =
150             "com.android.contextualsearch.LAUNCH";
151 
152 
153     final Context mContext;
154     final ContentResolver mResolver;
155     // Can be overridden for testing purposes
156     private IEnrolledModelDb mDbHelper;
157     private final IEnrolledModelDb mRealDbHelper;
158     final ActivityManagerInternal mAmInternal;
159     final ActivityTaskManagerInternal mAtmInternal;
160     final UserManagerInternal mUserManagerInternal;
161     final WindowManagerInternal mWmInternal;
162     final DevicePolicyManagerInternal mDpmInternal;
163     final ArrayMap<Integer, VoiceInteractionManagerServiceStub.SoundTriggerSession>
164             mLoadedKeyphraseIds = new ArrayMap<>();
165     ShortcutServiceInternal mShortcutServiceInternal;
166     SoundTriggerInternal mSoundTriggerInternal;
167 
168     private final RemoteCallbackList<IVoiceInteractionSessionListener>
169             mVoiceInteractionSessionListeners = new RemoteCallbackList<>();
170     private IVisualQueryRecognitionStatusListener mVisualQueryRecognitionStatusListener;
171 
VoiceInteractionManagerService(Context context)172     public VoiceInteractionManagerService(Context context) {
173         super(context);
174         mContext = context;
175         mResolver = context.getContentResolver();
176         mUserManagerInternal = Objects.requireNonNull(
177                 LocalServices.getService(UserManagerInternal.class));
178         mDbHelper = mRealDbHelper = new DatabaseHelper(context);
179         mServiceStub = new VoiceInteractionManagerServiceStub();
180         mAmInternal = Objects.requireNonNull(
181                 LocalServices.getService(ActivityManagerInternal.class));
182         mAtmInternal = Objects.requireNonNull(
183                 LocalServices.getService(ActivityTaskManagerInternal.class));
184         mWmInternal = Objects.requireNonNull(
185                 LocalServices.getService(WindowManagerInternal.class));
186         mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
187         LegacyPermissionManagerInternal permissionManagerInternal = LocalServices.getService(
188                 LegacyPermissionManagerInternal.class);
189         permissionManagerInternal.setVoiceInteractionPackagesProvider(
190                 new LegacyPermissionManagerInternal.PackagesProvider() {
191             @Override
192             public String[] getPackages(int userId) {
193                 mServiceStub.initForUser(userId);
194                 ComponentName interactor = mServiceStub.getCurInteractor(userId);
195                 if (interactor != null) {
196                     return new String[] {interactor.getPackageName()};
197                 }
198                 return null;
199             }
200         });
201     }
202 
203     @Override
onStart()204     public void onStart() {
205         publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
206         publishLocalService(VoiceInteractionManagerInternal.class, new LocalService());
207         mAmInternal.setVoiceInteractionManagerProvider(
208                 new ActivityManagerInternal.VoiceInteractionManagerProvider() {
209                     @Override
210                     public void notifyActivityDestroyed(IBinder activityToken) {
211                         if (DEBUG) {
212                             Slog.d(TAG, "notifyActivityDestroyed activityToken=" + activityToken);
213                         }
214                         mServiceStub.notifyActivityDestroyed(activityToken);
215                     }
216                 });
217     }
218 
219     @Override
onBootPhase(int phase)220     public void onBootPhase(int phase) {
221         if (PHASE_SYSTEM_SERVICES_READY == phase) {
222             mShortcutServiceInternal = Objects.requireNonNull(
223                     LocalServices.getService(ShortcutServiceInternal.class));
224             mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
225         } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
226             mServiceStub.systemRunning(isSafeMode());
227         } else if (phase == PHASE_BOOT_COMPLETED) {
228             mServiceStub.registerVoiceInteractionSessionListener(mLatencyLoggingListener);
229         }
230     }
231 
232     @Override
isUserSupported(@onNull TargetUser user)233     public boolean isUserSupported(@NonNull TargetUser user) {
234         return user.isFull();
235     }
236 
isUserSupported(@onNull UserInfo user)237     private boolean isUserSupported(@NonNull UserInfo user) {
238         return user.isFull();
239     }
240 
241     @Override
onUserStarting(@onNull TargetUser user)242     public void onUserStarting(@NonNull TargetUser user) {
243         if (DEBUG_USER) Slog.d(TAG, "onUserStarting(" + user + ")");
244 
245         mServiceStub.initForUser(user.getUserIdentifier());
246     }
247 
248     @Override
onUserUnlocking(@onNull TargetUser user)249     public void onUserUnlocking(@NonNull TargetUser user) {
250         if (DEBUG_USER) Slog.d(TAG, "onUserUnlocking(" + user + ")");
251 
252         mServiceStub.initForUser(user.getUserIdentifier());
253         mServiceStub.switchImplementationIfNeeded(false);
254     }
255 
256     @Override
onUserSwitching(@ullable TargetUser from, @NonNull TargetUser to)257     public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
258         if (DEBUG_USER) Slog.d(TAG, "onSwitchUser(" + from + " > " + to + ")");
259 
260         mServiceStub.switchUser(to.getUserIdentifier());
261     }
262 
263     class LocalService extends VoiceInteractionManagerInternal {
264         @Override
startLocalVoiceInteraction(@onNull IBinder callingActivity, @Nullable String attributionTag, @Nullable Bundle options)265         public void startLocalVoiceInteraction(@NonNull IBinder callingActivity,
266                 @Nullable String attributionTag, @Nullable Bundle options) {
267             if (DEBUG) {
268                 Slog.i(TAG, "startLocalVoiceInteraction " + callingActivity);
269             }
270             VoiceInteractionManagerService.this.mServiceStub.startLocalVoiceInteraction(
271                     callingActivity, attributionTag, options);
272         }
273 
274         @Override
supportsLocalVoiceInteraction()275         public boolean supportsLocalVoiceInteraction() {
276             return VoiceInteractionManagerService.this.mServiceStub.supportsLocalVoiceInteraction();
277         }
278 
279         @Override
stopLocalVoiceInteraction(IBinder callingActivity)280         public void stopLocalVoiceInteraction(IBinder callingActivity) {
281             if (DEBUG) {
282                 Slog.i(TAG, "stopLocalVoiceInteraction " + callingActivity);
283             }
284             VoiceInteractionManagerService.this.mServiceStub.stopLocalVoiceInteraction(
285                     callingActivity);
286         }
287 
288         @Override
hasActiveSession(String packageName)289         public boolean hasActiveSession(String packageName) {
290             VoiceInteractionManagerServiceImpl impl =
291                     VoiceInteractionManagerService.this.mServiceStub.mImpl;
292             if (impl == null) {
293                 return false;
294             }
295 
296             VoiceInteractionSessionConnection session =
297                     impl.mActiveSession;
298             if (session == null) {
299                 return false;
300             }
301 
302             return TextUtils.equals(packageName, session.mSessionComponentName.getPackageName());
303         }
304 
305         @Override
getVoiceInteractorPackageName(IBinder callingVoiceInteractor)306         public String getVoiceInteractorPackageName(IBinder callingVoiceInteractor) {
307             VoiceInteractionManagerServiceImpl impl =
308                     VoiceInteractionManagerService.this.mServiceStub.mImpl;
309             if (impl == null) {
310                 return null;
311             }
312             VoiceInteractionSessionConnection session =
313                     impl.mActiveSession;
314             if (session == null) {
315                 return null;
316             }
317             IVoiceInteractor voiceInteractor = session.mInteractor;
318             if (voiceInteractor == null || voiceInteractor.asBinder() != callingVoiceInteractor) {
319                 return null;
320             }
321             return session.mSessionComponentName.getPackageName();
322         }
323 
324         @Override
getHotwordDetectionServiceIdentity()325         public HotwordDetectionServiceIdentity getHotwordDetectionServiceIdentity() {
326             // IMPORTANT: This is called when performing permission checks; do not lock!
327 
328             // TODO: Have AppOpsPolicy register a listener instead of calling in here everytime.
329             // Then also remove the `volatile`s that were added with this method.
330 
331             VoiceInteractionManagerServiceImpl impl =
332                     VoiceInteractionManagerService.this.mServiceStub.mImpl;
333             if (impl == null) {
334                 return null;
335             }
336             HotwordDetectionConnection hotwordDetectionConnection =
337                     impl.mHotwordDetectionConnection;
338             if (hotwordDetectionConnection == null) {
339                 return null;
340             }
341             return hotwordDetectionConnection.mIdentity;
342         }
343 
344         // TODO(b/226201975): remove this method once RoleService supports pre-created users
345         @Override
onPreCreatedUserConversion(int userId)346         public void onPreCreatedUserConversion(int userId) {
347             Slogf.d(TAG, "onPreCreatedUserConversion(%d): calling onRoleHoldersChanged() again",
348                     userId);
349             mServiceStub.mRoleObserver.onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT,
350                                                 UserHandle.of(userId));
351         }
352 
353         @Override
startListeningFromWearable( ParcelFileDescriptor audioStreamFromWearable, AudioFormat audioFormatFromWearable, PersistableBundle options, ComponentName targetVisComponentName, int userId, WearableHotwordDetectionCallback callback)354         public void startListeningFromWearable(
355                 ParcelFileDescriptor audioStreamFromWearable,
356                 AudioFormat audioFormatFromWearable,
357                 PersistableBundle options,
358                 ComponentName targetVisComponentName,
359                 int userId,
360                 WearableHotwordDetectionCallback callback) {
361             Slog.d(TAG, "#startListeningFromWearable");
362             VoiceInteractionManagerServiceImpl impl = mServiceStub.mImpl;
363             if (impl == null) {
364                 callback.onError(
365                         "Unable to start listening from wearable because the service impl is"
366                                 + " null.");
367                 return;
368             }
369             if (targetVisComponentName != null && !targetVisComponentName.equals(impl.mComponent)) {
370                 callback.onError(
371                         TextUtils.formatSimple(
372                                 "Unable to start listening from wearable because the target"
373                                     + " VoiceInteractionService %s is different from the current"
374                                     + " VoiceInteractionService %s",
375                                 targetVisComponentName, impl.mComponent));
376                 return;
377             }
378             if (userId != impl.mUser) {
379                 callback.onError(
380                         TextUtils.formatSimple(
381                                 "Unable to start listening from wearable because the target userId"
382                                     + " %s is different from the current"
383                                     + " VoiceInteractionManagerServiceImpl's userId %s",
384                                 userId, impl.mUser));
385                 return;
386             }
387             synchronized (mServiceStub) {
388                 impl.startListeningFromWearableLocked(
389                         audioStreamFromWearable, audioFormatFromWearable, options, callback);
390             }
391         }
392     }
393 
394     // implementation entry point and binder service
395     private final VoiceInteractionManagerServiceStub mServiceStub;
396 
397     class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
398 
399         volatile VoiceInteractionManagerServiceImpl mImpl;
400 
401         private boolean mSafeMode;
402         private int mCurUser;
403         private boolean mCurUserSupported;
404 
405         @GuardedBy("this")
406         private boolean mTemporarilyDisabled;
407 
408         /** The start value of showSessionId */
409         private static final int SHOW_SESSION_START_ID = 0;
410 
411         private final boolean IS_HDS_REQUIRED = AppOpsPolicy.isHotwordDetectionServiceRequired(
412                 mContext.getPackageManager());
413 
414         @GuardedBy("this")
415         private int mShowSessionId = SHOW_SESSION_START_ID;
416 
417         private final boolean mEnableService;
418         // TODO(b/226201975): remove reference once RoleService supports pre-created users
419         private final RoleObserver mRoleObserver;
420 
VoiceInteractionManagerServiceStub()421         VoiceInteractionManagerServiceStub() {
422             mEnableService = shouldEnableService(mContext);
423             mRoleObserver = new RoleObserver(mContext.getMainExecutor());
424         }
425 
handleUserStop(String packageName, int userHandle)426         void handleUserStop(String packageName, int userHandle) {
427             synchronized (VoiceInteractionManagerServiceStub.this) {
428                 ComponentName curInteractor = getCurInteractor(userHandle);
429                 if (curInteractor != null && packageName.equals(curInteractor.getPackageName())) {
430                     Slog.d(TAG, "switchImplementation for user stop.");
431                     switchImplementationIfNeededLocked(true);
432                 }
433             }
434         }
435 
getNextShowSessionId()436         int getNextShowSessionId() {
437             synchronized (this) {
438                 // Reset the showSessionId to SHOW_SESSION_START_ID to avoid the value exceeds
439                 // Integer.MAX_VALUE
440                 if (mShowSessionId == Integer.MAX_VALUE - 1) {
441                     mShowSessionId = SHOW_SESSION_START_ID;
442                 }
443                 mShowSessionId++;
444                 return mShowSessionId;
445             }
446         }
447 
getShowSessionId()448         int getShowSessionId() {
449             synchronized (this) {
450                 return mShowSessionId;
451             }
452         }
453 
454         @Override
createSoundTriggerSessionAsOriginator( @onNull Identity originatorIdentity, IBinder client, ModuleProperties moduleProperties)455         public @NonNull IVoiceInteractionSoundTriggerSession createSoundTriggerSessionAsOriginator(
456                 @NonNull Identity originatorIdentity, IBinder client,
457                 ModuleProperties moduleProperties) {
458             Objects.requireNonNull(originatorIdentity);
459             boolean forHotwordDetectionService = false;
460             synchronized (VoiceInteractionManagerServiceStub.this) {
461                 enforceIsCurrentVoiceInteractionService();
462                 forHotwordDetectionService =
463                         mImpl != null && mImpl.mHotwordDetectionConnection != null;
464             }
465             if (HotwordDetectionConnection.DEBUG) {
466                 Slog.d(TAG, "Creating a SoundTriggerSession, for HDS: "
467                         + forHotwordDetectionService);
468             }
469             try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
470                     originatorIdentity)) {
471                 if (!IS_HDS_REQUIRED) {
472                     // For devices which still have hotword exemption, any client (not just HDS
473                     // clients) are trusted.
474                     // TODO (b/292012931) remove once trusted uniformly required.
475                     forHotwordDetectionService = true;
476                 }
477                 return new SoundTriggerSession(mSoundTriggerInternal.attach(client,
478                             moduleProperties, forHotwordDetectionService), originatorIdentity);
479             }
480         }
481 
482         @Override
listModuleProperties(Identity originatorIdentity)483         public List<ModuleProperties> listModuleProperties(Identity originatorIdentity) {
484             synchronized (VoiceInteractionManagerServiceStub.this) {
485                 enforceIsCurrentVoiceInteractionService();
486             }
487             return mSoundTriggerInternal.listModuleProperties(originatorIdentity);
488         }
489 
490         // TODO: VI Make sure the caller is the current user or profile
startLocalVoiceInteraction(@onNull final IBinder token, @Nullable String attributionTag, @Nullable Bundle options)491         void startLocalVoiceInteraction(@NonNull final IBinder token,
492                 @Nullable String attributionTag, @Nullable Bundle options) {
493             if (mImpl == null) return;
494 
495             final int callingUid = Binder.getCallingUid();
496             final long caller = Binder.clearCallingIdentity();
497             try {
498                 // HotwordDetector trigger uses VoiceInteractionService#showSession
499                 // We need to cancel here because UI is not being shown due to a SoundTrigger
500                 // HAL event.
501                 HotwordMetricsLogger.cancelHotwordTriggerToUiLatencySession(mContext);
502                 mImpl.showSessionLocked(options,
503                         VoiceInteractionSession.SHOW_SOURCE_ACTIVITY, attributionTag,
504                         new IVoiceInteractionSessionShowCallback.Stub() {
505                             @Override
506                             public void onFailed() {
507                             }
508 
509                             @Override
510                             public void onShown() {
511                                 synchronized (VoiceInteractionManagerServiceStub.this) {
512                                     if (mImpl != null) {
513                                         mImpl.grantImplicitAccessLocked(callingUid,
514                                                 /* intent= */ null);
515                                     }
516                                 }
517                                 mAtmInternal.onLocalVoiceInteractionStarted(token,
518                                         mImpl.mActiveSession.mSession,
519                                         mImpl.mActiveSession.mInteractor);
520                             }
521                         },
522                         token);
523             } finally {
524                 Binder.restoreCallingIdentity(caller);
525             }
526         }
527 
stopLocalVoiceInteraction(IBinder callingActivity)528         public void stopLocalVoiceInteraction(IBinder callingActivity) {
529             if (mImpl == null) return;
530 
531             final long caller = Binder.clearCallingIdentity();
532             try {
533                 mImpl.finishLocked(callingActivity, true);
534             } finally {
535                 Binder.restoreCallingIdentity(caller);
536             }
537         }
538 
supportsLocalVoiceInteraction()539         public boolean supportsLocalVoiceInteraction() {
540             if (mImpl == null) return false;
541 
542             return mImpl.supportsLocalVoiceInteraction();
543         }
544 
notifyActivityDestroyed(@onNull IBinder activityToken)545         void notifyActivityDestroyed(@NonNull IBinder activityToken) {
546             synchronized (this) {
547                 if (mImpl == null || activityToken == null) return;
548 
549                 Binder.withCleanCallingIdentity(
550                         () -> mImpl.notifyActivityDestroyedLocked(activityToken));
551             }
552         }
553 
554         @Override
onTransact(int code, Parcel data, Parcel reply, int flags)555         public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
556                 throws RemoteException {
557             try {
558                 return super.onTransact(code, data, reply, flags);
559             } catch (RuntimeException e) {
560                 // The activity manager only throws security exceptions, so let's
561                 // log all others.
562                 if (!(e instanceof SecurityException)) {
563                     Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e);
564                 }
565                 throw e;
566             }
567         }
568 
initForUser(int userHandle)569         public void initForUser(int userHandle) {
570             final TimingsTraceAndSlog t;
571             if (DEBUG_USER) {
572                 t = new TimingsTraceAndSlog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
573                 t.traceBegin("initForUser(" + userHandle + ")");
574             } else {
575                 t = null;
576             }
577             initForUserNoTracing(userHandle);
578             if (t != null) {
579                 t.traceEnd();
580             }
581         }
582 
initForUserNoTracing(@serIdInt int userHandle)583         private void initForUserNoTracing(@UserIdInt int userHandle) {
584             if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle);
585             String curInteractorStr = Settings.Secure.getStringForUser(
586                     mContext.getContentResolver(),
587                     Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
588             ComponentName curRecognizer = getCurRecognizer(userHandle);
589             VoiceInteractionServiceInfo curInteractorInfo = null;
590             if (DEBUG) {
591                 Slog.d(TAG, "curInteractorStr=" + curInteractorStr
592                         + " curRecognizer=" + curRecognizer
593                         + " mEnableService=" + mEnableService
594                         + " mTemporarilyDisabled=" + mTemporarilyDisabled);
595             }
596             if (curInteractorStr == null && curRecognizer != null && mEnableService) {
597                 // If there is no interactor setting, that means we are upgrading
598                 // from an older platform version.  If the current recognizer is not
599                 // set or matches the preferred recognizer, then we want to upgrade
600                 // the user to have the default voice interaction service enabled.
601                 // Note that we don't do this for low-RAM devices, since we aren't
602                 // supporting voice interaction services there.
603                 curInteractorInfo = findAvailInteractor(userHandle, curRecognizer.getPackageName());
604                 if (curInteractorInfo != null) {
605                     // Looks good!  We'll apply this one.  To make it happen, we clear the
606                     // recognizer so that we don't think we have anything set and will
607                     // re-apply the settings.
608                     if (DEBUG) Slog.d(TAG, "No set interactor, found avail: "
609                             + curInteractorInfo.getServiceInfo().name);
610                     curRecognizer = null;
611                 }
612             }
613 
614             // If forceInteractorPackage exists, try to apply the interactor from this package if
615             // possible and ignore the regular interactor setting.
616             String forceInteractorPackage =
617                     getForceVoiceInteractionServicePackage(mContext.getResources());
618             if (forceInteractorPackage != null) {
619                 curInteractorInfo = findAvailInteractor(userHandle, forceInteractorPackage);
620                 if (curInteractorInfo != null) {
621                     // We'll apply this one. Clear the recognizer and re-apply the settings.
622                     curRecognizer = null;
623                 }
624             }
625 
626             // If we are on a svelte device, make sure an interactor is not currently
627             // enabled; if it is, turn it off.
628             if (!mEnableService && curInteractorStr != null) {
629                 if (!TextUtils.isEmpty(curInteractorStr)) {
630                     if (DEBUG) Slog.d(TAG, "Svelte device; disabling interactor");
631                     setCurInteractor(null, userHandle);
632                     curInteractorStr = "";
633                 }
634             }
635 
636             if (curRecognizer != null) {
637                 // If we already have at least a recognizer, then we probably want to
638                 // leave things as they are...  unless something has disappeared.
639                 IPackageManager pm = AppGlobals.getPackageManager();
640                 ServiceInfo interactorInfo = null;
641                 ServiceInfo recognizerInfo = null;
642                 ComponentName curInteractor = !TextUtils.isEmpty(curInteractorStr)
643                         ? ComponentName.unflattenFromString(curInteractorStr) : null;
644                 try {
645                     recognizerInfo = pm.getServiceInfo(
646                             curRecognizer,
647                             PackageManager.MATCH_DIRECT_BOOT_AWARE
648                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
649                                     | PackageManager.GET_META_DATA,
650                             userHandle);
651                     if (recognizerInfo != null) {
652                         RecognitionServiceInfo rsi =
653                                 RecognitionServiceInfo.parseInfo(
654                                         mContext.getPackageManager(), recognizerInfo);
655                         if (!TextUtils.isEmpty(rsi.getParseError())) {
656                             Log.w(TAG, "Parse error in getAvailableServices: "
657                                     + rsi.getParseError());
658                             // We still use the recognizer to preserve pre-existing behavior.
659                         }
660                         if (!rsi.isSelectableAsDefault()) {
661                             if (DEBUG) {
662                                 Slog.d(TAG, "Found non selectableAsDefault recognizer as"
663                                         + " default. Unsetting the default and looking for another"
664                                         + " one.");
665                             }
666                             recognizerInfo = null;
667                         }
668                     }
669                     if (curInteractor != null) {
670                         interactorInfo = pm.getServiceInfo(curInteractor,
671                                 PackageManager.MATCH_DIRECT_BOOT_AWARE
672                                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
673                     }
674                 } catch (RemoteException e) {
675                 }
676                 // If the apps for the currently set components still exist, then all is okay.
677                 if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) {
678                     if (DEBUG) Slog.d(TAG, "Current interactor/recognizer okay, done!");
679                     return;
680                 }
681                 if (DEBUG) Slog.d(TAG, "Bad recognizer (" + recognizerInfo + ") or interactor ("
682                         + interactorInfo + ")");
683             }
684 
685             // Initializing settings. Look for an interactor first, but only on non-svelte and only
686             // if the user hasn't explicitly unset it.
687             if (curInteractorInfo == null && mEnableService && !"".equals(curInteractorStr)) {
688                 curInteractorInfo = findAvailInteractor(userHandle, null);
689             }
690 
691             if (curInteractorInfo != null) {
692                 // Eventually it will be an error to not specify this.
693                 setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName,
694                         curInteractorInfo.getServiceInfo().name), userHandle);
695             } else {
696                 // No voice interactor, so clear the setting.
697                 setCurInteractor(null, userHandle);
698             }
699 
700             initRecognizer(userHandle);
701         }
702 
initRecognizer(int userHandle)703         public void initRecognizer(int userHandle) {
704             ComponentName curRecognizer = findAvailRecognizer(null, userHandle);
705             if (curRecognizer != null) {
706                 setCurRecognizer(curRecognizer, userHandle);
707             }
708         }
709 
shouldEnableService(Context context)710         private boolean shouldEnableService(Context context) {
711             // VoiceInteractionService should not be enabled on devices that have not declared the
712             // recognition feature (including low-ram devices where notLowRam="true" takes effect),
713             // unless the device's configuration has explicitly set the config flag for a fixed
714             // voice interaction service.
715             if (getForceVoiceInteractionServicePackage(context.getResources()) != null) {
716                 return true;
717             }
718             return context.getPackageManager()
719                     .hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS);
720         }
721 
getForceVoiceInteractionServicePackage(Resources res)722         private String getForceVoiceInteractionServicePackage(Resources res) {
723             String interactorPackage = res.getString(
724                     com.android.internal.R.string.config_forceVoiceInteractionServicePackage);
725             return TextUtils.isEmpty(interactorPackage) ? null : interactorPackage;
726         }
727 
systemRunning(boolean safeMode)728         public void systemRunning(boolean safeMode) {
729             mSafeMode = safeMode;
730 
731             mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(),
732                     UserHandle.ALL, true);
733             new SettingsObserver(UiThread.getHandler());
734 
735             synchronized (this) {
736                 setCurrentUserLocked(ActivityManager.getCurrentUser());
737                 switchImplementationIfNeededLocked(false);
738             }
739         }
740 
setCurrentUserLocked(@serIdInt int userHandle)741         private void setCurrentUserLocked(@UserIdInt int userHandle) {
742             mCurUser = userHandle;
743             final UserInfo userInfo = mUserManagerInternal.getUserInfo(mCurUser);
744             mCurUserSupported = isUserSupported(userInfo);
745         }
746 
switchUser(@serIdInt int userHandle)747         public void switchUser(@UserIdInt int userHandle) {
748             FgThread.getHandler().post(() -> {
749                 synchronized (this) {
750                     setCurrentUserLocked(userHandle);
751                     switchImplementationIfNeededLocked(false);
752                 }
753             });
754         }
755 
switchImplementationIfNeeded(boolean force)756         void switchImplementationIfNeeded(boolean force) {
757             synchronized (this) {
758                 switchImplementationIfNeededLocked(force);
759             }
760         }
761 
switchImplementationIfNeededLocked(boolean force)762         void switchImplementationIfNeededLocked(boolean force) {
763             if (!mCurUserSupported) {
764                 if (DEBUG_USER) {
765                     Slog.d(TAG, "switchImplementationIfNeeded(): skipping: force= " + force
766                             + "mCurUserSupported=" + mCurUserSupported);
767                 }
768                 if (mImpl != null) {
769                     mImpl.shutdownLocked();
770                     setImplLocked(null);
771                 }
772                 return;
773             }
774 
775             final TimingsTraceAndSlog t;
776             if (DEBUG_USER) {
777                 t = new TimingsTraceAndSlog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
778                 t.traceBegin("switchImplementation(" + mCurUser + ")");
779             } else {
780                 t = null;
781             }
782             switchImplementationIfNeededNoTracingLocked(force);
783             if (t != null) {
784                 t.traceEnd();
785             }
786         }
787 
switchImplementationIfNeededNoTracingLocked(boolean force)788         void switchImplementationIfNeededNoTracingLocked(boolean force) {
789             if (!mSafeMode) {
790                 String curService = Settings.Secure.getStringForUser(
791                         mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
792                 ComponentName serviceComponent = null;
793                 ServiceInfo serviceInfo = null;
794                 if (curService != null && !curService.isEmpty()) {
795                     try {
796                         serviceComponent = ComponentName.unflattenFromString(curService);
797                         serviceInfo = AppGlobals.getPackageManager()
798                                 .getServiceInfo(serviceComponent, 0, mCurUser);
799                     } catch (RuntimeException | RemoteException e) {
800                         Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
801                         serviceComponent = null;
802                         serviceInfo = null;
803                     }
804                 }
805 
806                 final boolean hasComponent = serviceComponent != null && serviceInfo != null;
807 
808                 if (mUserManagerInternal.isUserUnlockingOrUnlocked(mCurUser)) {
809                     if (hasComponent) {
810                         mShortcutServiceInternal.setShortcutHostPackage(TAG,
811                                 serviceComponent.getPackageName(), mCurUser);
812                         mAtmInternal.setAllowAppSwitches(TAG,
813                                 serviceInfo.applicationInfo.uid, mCurUser);
814                     } else {
815                         mShortcutServiceInternal.setShortcutHostPackage(TAG, null, mCurUser);
816                         mAtmInternal.setAllowAppSwitches(TAG, -1, mCurUser);
817                     }
818                 }
819 
820                 if (force || mImpl == null || mImpl.mUser != mCurUser
821                         || !mImpl.mComponent.equals(serviceComponent)) {
822                     unloadAllKeyphraseModels();
823                     if (mImpl != null) {
824                         mImpl.shutdownLocked();
825                     }
826                     if (hasComponent) {
827                         setImplLocked(new VoiceInteractionManagerServiceImpl(mContext,
828                                 UiThread.getHandler(), this, mCurUser, serviceComponent));
829                         mImpl.startLocked();
830                     } else {
831                         setImplLocked(null);
832                     }
833                 }
834             }
835         }
836 
queryInteractorServices( @serIdInt int user, @Nullable String packageName)837         private List<ResolveInfo> queryInteractorServices(
838                 @UserIdInt int user,
839                 @Nullable String packageName) {
840             return mContext.getPackageManager().queryIntentServicesAsUser(
841                     new Intent(VoiceInteractionService.SERVICE_INTERFACE).setPackage(packageName),
842                     PackageManager.GET_META_DATA
843                             | PackageManager.MATCH_DIRECT_BOOT_AWARE
844                             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
845                     user);
846         }
847 
findAvailInteractor( @serIdInt int user, @Nullable String packageName)848         VoiceInteractionServiceInfo findAvailInteractor(
849                 @UserIdInt int user,
850                 @Nullable String packageName) {
851             List<ResolveInfo> available = queryInteractorServices(user, packageName);
852             int numAvailable = available.size();
853             if (numAvailable == 0) {
854                 Slog.w(TAG, "no available voice interaction services found for user " + user);
855                 return null;
856             }
857             // Find first system package.  We never want to allow third party services to
858             // be automatically selected, because those require approval of the user.
859             VoiceInteractionServiceInfo foundInfo = null;
860             for (int i = 0; i < numAvailable; i++) {
861                 ServiceInfo cur = available.get(i).serviceInfo;
862                 if ((cur.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
863                     continue;
864                 }
865                 VoiceInteractionServiceInfo info =
866                         new VoiceInteractionServiceInfo(mContext.getPackageManager(), cur);
867                 if (info.getParseError() != null) {
868                     Slog.w(TAG,
869                             "Bad interaction service " + cur.packageName + "/"
870                                     + cur.name + ": " + info.getParseError());
871                 } else if (foundInfo == null) {
872                     foundInfo = info;
873                 } else {
874                     Slog.w(TAG, "More than one voice interaction service, "
875                             + "picking first "
876                             + new ComponentName(
877                             foundInfo.getServiceInfo().packageName,
878                             foundInfo.getServiceInfo().name)
879                             + " over "
880                             + new ComponentName(cur.packageName, cur.name));
881                 }
882             }
883             return foundInfo;
884         }
885 
getCurInteractor(int userHandle)886         ComponentName getCurInteractor(int userHandle) {
887             String curInteractor = Settings.Secure.getStringForUser(
888                     mContext.getContentResolver(),
889                     Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
890             if (TextUtils.isEmpty(curInteractor)) {
891                 return null;
892             }
893             if (DEBUG) {
894                 Slog.d(TAG, "getCurInteractor curInteractor=" + curInteractor
895                     + " user=" + userHandle);
896             }
897             return ComponentName.unflattenFromString(curInteractor);
898         }
899 
setCurInteractor(ComponentName comp, int userHandle)900         void setCurInteractor(ComponentName comp, int userHandle) {
901             Settings.Secure.putStringForUser(mContext.getContentResolver(),
902                     Settings.Secure.VOICE_INTERACTION_SERVICE,
903                     comp != null ? comp.flattenToShortString() : "", userHandle);
904             if (DEBUG) {
905                 Slog.d(TAG, "setCurInteractor comp=" + comp + " user=" + userHandle);
906             }
907         }
908 
findAvailRecognizer(String prefPackage, int userHandle)909         ComponentName findAvailRecognizer(String prefPackage, int userHandle) {
910             if (prefPackage == null) {
911                 prefPackage = getDefaultRecognizer();
912             }
913 
914             List<RecognitionServiceInfo> available =
915                     RecognitionServiceInfo.getAvailableServices(mContext, userHandle);
916             if (available.size() == 0) {
917                 Slog.w(TAG, "no available voice recognition services found for user " + userHandle);
918                 return null;
919             } else {
920                 List<RecognitionServiceInfo> nonSelectableAsDefault =
921                         removeNonSelectableAsDefault(available);
922                 if (available.size() == 0) {
923                     Slog.w(TAG, "No selectableAsDefault recognition services found for user "
924                             + userHandle + ". Falling back to non selectableAsDefault ones.");
925                     available = nonSelectableAsDefault;
926                 }
927                 int numAvailable = available.size();
928                 if (prefPackage != null) {
929                     for (int i = 0; i < numAvailable; i++) {
930                         ServiceInfo serviceInfo = available.get(i).getServiceInfo();
931                         if (prefPackage.equals(serviceInfo.packageName)) {
932                             return new ComponentName(serviceInfo.packageName, serviceInfo.name);
933                         }
934                     }
935                 }
936                 if (numAvailable > 1) {
937                     Slog.w(TAG, "more than one voice recognition service found, picking first");
938                 }
939 
940                 ServiceInfo serviceInfo = available.get(0).getServiceInfo();
941                 return new ComponentName(serviceInfo.packageName, serviceInfo.name);
942             }
943         }
944 
removeNonSelectableAsDefault( List<RecognitionServiceInfo> services)945         private List<RecognitionServiceInfo> removeNonSelectableAsDefault(
946                 List<RecognitionServiceInfo> services) {
947             List<RecognitionServiceInfo> nonSelectableAsDefault = new ArrayList<>();
948             for (int i = services.size() - 1; i >= 0; i--) {
949                 if (!services.get(i).isSelectableAsDefault()) {
950                     nonSelectableAsDefault.add(services.remove(i));
951                 }
952             }
953             return nonSelectableAsDefault;
954         }
955 
956         @Nullable
getDefaultRecognizer()957         public String getDefaultRecognizer() {
958             String recognizer = mContext.getString(R.string.config_systemSpeechRecognizer);
959             return TextUtils.isEmpty(recognizer) ? null : recognizer;
960         }
961 
getCurRecognizer(int userHandle)962         ComponentName getCurRecognizer(int userHandle) {
963             String curRecognizer = Settings.Secure.getStringForUser(
964                     mContext.getContentResolver(),
965                     Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle);
966             if (TextUtils.isEmpty(curRecognizer)) {
967                 return null;
968             }
969             if (DEBUG) Slog.d(TAG, "getCurRecognizer curRecognizer=" + curRecognizer
970                     + " user=" + userHandle);
971             return ComponentName.unflattenFromString(curRecognizer);
972         }
973 
setCurRecognizer(ComponentName comp, int userHandle)974         void setCurRecognizer(ComponentName comp, int userHandle) {
975             Settings.Secure.putStringForUser(mContext.getContentResolver(),
976                     Settings.Secure.VOICE_RECOGNITION_SERVICE,
977                     comp != null ? comp.flattenToShortString() : "", userHandle);
978             if (DEBUG) Slog.d(TAG, "setCurRecognizer comp=" + comp
979                     + " user=" + userHandle);
980         }
981 
getCurAssistant(int userHandle)982         ComponentName getCurAssistant(int userHandle) {
983             String curAssistant = Settings.Secure.getStringForUser(
984                     mContext.getContentResolver(),
985                     Settings.Secure.ASSISTANT, userHandle);
986             if (TextUtils.isEmpty(curAssistant)) {
987                 return null;
988             }
989             if (DEBUG) Slog.d(TAG, "getCurAssistant curAssistant=" + curAssistant
990                     + " user=" + userHandle);
991             return ComponentName.unflattenFromString(curAssistant);
992         }
993 
resetCurAssistant(int userHandle)994         void resetCurAssistant(int userHandle) {
995             Settings.Secure.putStringForUser(mContext.getContentResolver(),
996                     Settings.Secure.ASSISTANT, null, userHandle);
997         }
998 
forceRestartHotwordDetector()999         void forceRestartHotwordDetector() {
1000             mImpl.forceRestartHotwordDetector();
1001         }
1002 
1003         // Called by Shell command
setDebugHotwordLogging(boolean logging)1004         void setDebugHotwordLogging(boolean logging) {
1005             synchronized (this) {
1006                 if (mImpl == null) {
1007                     Slog.w(TAG, "setTemporaryLogging without running voice interaction service");
1008                     return;
1009                 }
1010                 mImpl.setDebugHotwordLoggingLocked(logging);
1011             }
1012         }
1013 
1014         @Override
showSession(@ullable Bundle args, int flags, @Nullable String attributionTag)1015         public void showSession(@Nullable Bundle args, int flags, @Nullable String attributionTag) {
1016             synchronized (this) {
1017                 enforceIsCurrentVoiceInteractionService();
1018 
1019                 final long caller = Binder.clearCallingIdentity();
1020                 try {
1021                     mImpl.showSessionLocked(args, flags, attributionTag, null, null);
1022                 } finally {
1023                     Binder.restoreCallingIdentity(caller);
1024                 }
1025             }
1026         }
1027 
1028         @Override
deliverNewSession(IBinder token, IVoiceInteractionSession session, IVoiceInteractor interactor)1029         public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
1030                 IVoiceInteractor interactor) {
1031             synchronized (this) {
1032                 if (mImpl == null) {
1033                     throw new SecurityException(
1034                             "deliverNewSession without running voice interaction service");
1035                 }
1036                 final long caller = Binder.clearCallingIdentity();
1037                 try {
1038                     return mImpl.deliverNewSessionLocked(token, session, interactor);
1039                 } finally {
1040                     Binder.restoreCallingIdentity(caller);
1041                 }
1042             }
1043         }
1044 
1045         @Override
showSessionFromSession(@onNull IBinder token, @Nullable Bundle sessionArgs, int flags, @Nullable String attributionTag)1046         public boolean showSessionFromSession(@NonNull IBinder token, @Nullable Bundle sessionArgs,
1047                 int flags, @Nullable String attributionTag) {
1048             synchronized (this) {
1049                 final String csKey = mContext.getResources()
1050                         .getString(R.string.config_defaultContextualSearchKey);
1051                 final String csEnabledKey = mContext.getResources()
1052                         .getString(R.string.config_defaultContextualSearchEnabled);
1053 
1054                 // If the request is for Contextual Search, process it differently
1055                 if (sessionArgs != null && sessionArgs.containsKey(csKey)) {
1056                     if (sessionArgs.getBoolean(csEnabledKey, true)) {
1057                         // If Contextual Search is enabled, try to follow that path.
1058                         Intent launchIntent;
1059                         final long getSearchIntentCaller = Binder.clearCallingIdentity();
1060                         try {
1061                             launchIntent = getContextualSearchIntent(sessionArgs);
1062                         } finally {
1063                             Binder.restoreCallingIdentity(getSearchIntentCaller);
1064                         }
1065                         if (launchIntent != null) {
1066                             // Hand over to contextual search helper.
1067                             Slog.d(TAG, "Handed over to contextual search helper.");
1068                             final int userId = Binder.getCallingUserHandle().getIdentifier();
1069                             final long startSearchCaller = Binder.clearCallingIdentity();
1070                             try {
1071                                 return startContextualSearch(launchIntent, userId);
1072                             } finally {
1073                                 Binder.restoreCallingIdentity(startSearchCaller);
1074                             }
1075                         }
1076                     }
1077 
1078                     // Since we are here, Contextual Search helper couldn't handle the request.
1079                     final String visEnabledKey = mContext.getResources()
1080                             .getString(R.string.config_defaultContextualSearchLegacyEnabled);
1081                     if (sessionArgs.getBoolean(visEnabledKey, true)) {
1082                         // If visEnabledKey is set to true (or absent), we try following VIS path.
1083                         String csPkgName = mContext.getResources()
1084                                 .getString(R.string.config_defaultContextualSearchPackageName);
1085                         ComponentName currInteractor =
1086                                 getCurInteractor(Binder.getCallingUserHandle().getIdentifier());
1087                         if (currInteractor == null
1088                                 || !csPkgName.equals(currInteractor.getPackageName())) {
1089                             // Check if the interactor can handle Contextual Search.
1090                             // If not, return failure.
1091                             Slog.w(TAG, "Contextual Search not supported yet. Returning failure.");
1092                             return false;
1093                         }
1094                     } else {
1095                         // If visEnabledKey is set to false AND the request was for Contextual
1096                         // Search, return false.
1097                         return false;
1098                     }
1099                     // Given that we haven't returned yet, we can say that
1100                     // - Contextual Search Helper couldn't handle the request
1101                     // - VIS path for Contextual Search is enabled
1102                     // - The current interactor supports Contextual Search.
1103                     // Hence, we will proceed with the VIS path.
1104                     Slog.d(TAG, "Contextual search not supported yet. Proceeding with VIS.");
1105 
1106                 }
1107 
1108                 if (mImpl == null) {
1109                     Slog.w(TAG, "showSessionFromSession without running voice interaction service");
1110                     return false;
1111                 }
1112                 // If the token is null, then the request to show the session is not coming from
1113                 // the active VoiceInteractionService session.
1114                 // We need to cancel here because UI is not being shown due to a SoundTrigger
1115                 // HAL event.
1116                 if (token == null) {
1117                     HotwordMetricsLogger.cancelHotwordTriggerToUiLatencySession(mContext);
1118                 }
1119                 final long caller = Binder.clearCallingIdentity();
1120                 try {
1121                     return mImpl.showSessionLocked(sessionArgs, flags, attributionTag, null, null);
1122                 } finally {
1123                     Binder.restoreCallingIdentity(caller);
1124                 }
1125             }
1126         }
1127 
1128         @Override
hideSessionFromSession(IBinder token)1129         public boolean hideSessionFromSession(IBinder token) {
1130             synchronized (this) {
1131                 if (mImpl == null) {
1132                     Slog.w(TAG, "hideSessionFromSession without running voice interaction service");
1133                     return false;
1134                 }
1135                 final long caller = Binder.clearCallingIdentity();
1136                 try {
1137                     return mImpl.hideSessionLocked();
1138                 } finally {
1139                     Binder.restoreCallingIdentity(caller);
1140                 }
1141             }
1142         }
1143 
1144         @Override
startVoiceActivity(@onNull IBinder token, @NonNull Intent intent, @Nullable String resolvedType, @Nullable String attributionTag)1145         public int startVoiceActivity(@NonNull IBinder token, @NonNull Intent intent,
1146                 @Nullable String resolvedType, @Nullable String attributionTag) {
1147             synchronized (this) {
1148                 if (mImpl == null) {
1149                     Slog.w(TAG, "startVoiceActivity without running voice interaction service");
1150                     return ActivityManager.START_CANCELED;
1151                 }
1152                 final int callingPid = Binder.getCallingPid();
1153                 final int callingUid = Binder.getCallingUid();
1154                 final long caller = Binder.clearCallingIdentity();
1155                 try {
1156                     final ActivityInfo activityInfo = intent.resolveActivityInfo(
1157                             mContext.getPackageManager(), PackageManager.MATCH_ALL);
1158                     if (activityInfo != null) {
1159                         final int activityUid = activityInfo.applicationInfo.uid;
1160                         mImpl.grantImplicitAccessLocked(activityUid, intent);
1161                     } else {
1162                         Slog.w(TAG, "Cannot find ActivityInfo in startVoiceActivity.");
1163                     }
1164                     return mImpl.startVoiceActivityLocked(attributionTag, callingPid, callingUid,
1165                             token, intent, resolvedType);
1166                 } finally {
1167                     Binder.restoreCallingIdentity(caller);
1168                 }
1169             }
1170         }
1171 
1172         @Override
startAssistantActivity(@onNull IBinder token, @NonNull Intent intent, @Nullable String resolvedType, @NonNull String attributionTag, @NonNull Bundle bundle)1173         public int startAssistantActivity(@NonNull IBinder token, @NonNull Intent intent,
1174                 @Nullable String resolvedType, @NonNull String attributionTag,
1175                 @NonNull Bundle bundle) {
1176             synchronized (this) {
1177                 if (mImpl == null) {
1178                     Slog.w(TAG, "startAssistantActivity without running voice interaction service");
1179                     return ActivityManager.START_CANCELED;
1180                 }
1181                 final int callingPid = Binder.getCallingPid();
1182                 final int callingUid = Binder.getCallingUid();
1183                 final long caller = Binder.clearCallingIdentity();
1184                 try {
1185                     return mImpl.startAssistantActivityLocked(attributionTag, callingPid,
1186                             callingUid, token, intent, resolvedType, bundle);
1187                 } finally {
1188                     Binder.restoreCallingIdentity(caller);
1189                 }
1190             }
1191         }
1192 
1193         @Override
requestDirectActions(@onNull IBinder token, int taskId, @NonNull IBinder assistToken, @Nullable RemoteCallback cancellationCallback, @NonNull RemoteCallback resultCallback)1194         public void requestDirectActions(@NonNull IBinder token, int taskId,
1195                 @NonNull IBinder assistToken, @Nullable RemoteCallback cancellationCallback,
1196                 @NonNull RemoteCallback resultCallback) {
1197             synchronized (this) {
1198                 if (mImpl == null) {
1199                     Slog.w(TAG, "requestDirectActions without running voice interaction service");
1200                     resultCallback.sendResult(null);
1201                     return;
1202                 }
1203                 final long caller = Binder.clearCallingIdentity();
1204                 try {
1205                     mImpl.requestDirectActionsLocked(token, taskId, assistToken,
1206                             cancellationCallback, resultCallback);
1207                 } finally {
1208                     Binder.restoreCallingIdentity(caller);
1209                 }
1210             }
1211         }
1212 
1213         @Override
performDirectAction(@onNull IBinder token, @NonNull String actionId, @NonNull Bundle arguments, int taskId, IBinder assistToken, @Nullable RemoteCallback cancellationCallback, @NonNull RemoteCallback resultCallback)1214         public void performDirectAction(@NonNull IBinder token, @NonNull String actionId,
1215                 @NonNull Bundle arguments, int taskId, IBinder assistToken,
1216                 @Nullable RemoteCallback cancellationCallback,
1217                 @NonNull RemoteCallback resultCallback) {
1218             synchronized (this) {
1219                 if (mImpl == null) {
1220                     Slog.w(TAG, "performDirectAction without running voice interaction service");
1221                     resultCallback.sendResult(null);
1222                     return;
1223                 }
1224                 final long caller = Binder.clearCallingIdentity();
1225                 try {
1226                     mImpl.performDirectActionLocked(token, actionId, arguments, taskId,
1227                             assistToken, cancellationCallback, resultCallback);
1228                 } finally {
1229                     Binder.restoreCallingIdentity(caller);
1230                 }
1231             }
1232         }
1233 
1234         @Override
setKeepAwake(IBinder token, boolean keepAwake)1235         public void setKeepAwake(IBinder token, boolean keepAwake) {
1236             synchronized (this) {
1237                 if (mImpl == null) {
1238                     Slog.w(TAG, "setKeepAwake without running voice interaction service");
1239                     return;
1240                 }
1241                 final long caller = Binder.clearCallingIdentity();
1242                 try {
1243                     mImpl.setKeepAwakeLocked(token, keepAwake);
1244                 } finally {
1245                     Binder.restoreCallingIdentity(caller);
1246                 }
1247             }
1248         }
1249 
1250         @Override
closeSystemDialogs(IBinder token)1251         public void closeSystemDialogs(IBinder token) {
1252             synchronized (this) {
1253                 if (mImpl == null) {
1254                     Slog.w(TAG, "closeSystemDialogs without running voice interaction service");
1255                     return;
1256                 }
1257                 final long caller = Binder.clearCallingIdentity();
1258                 try {
1259                     mImpl.closeSystemDialogsLocked(token);
1260                 } finally {
1261                     Binder.restoreCallingIdentity(caller);
1262                 }
1263             }
1264         }
1265 
1266         @Override
finish(IBinder token)1267         public void finish(IBinder token) {
1268             synchronized (this) {
1269                 if (mImpl == null) {
1270                     Slog.w(TAG, "finish without running voice interaction service");
1271                     return;
1272                 }
1273                 final long caller = Binder.clearCallingIdentity();
1274                 try {
1275                     mImpl.finishLocked(token, false);
1276                 } finally {
1277                     Binder.restoreCallingIdentity(caller);
1278                 }
1279             }
1280         }
1281 
1282         @Override
setDisabledShowContext(int flags)1283         public void setDisabledShowContext(int flags) {
1284             synchronized (this) {
1285                 if (mImpl == null) {
1286                     Slog.w(TAG, "setDisabledShowContext without running voice interaction service");
1287                     return;
1288                 }
1289                 final int callingUid = Binder.getCallingUid();
1290                 final long caller = Binder.clearCallingIdentity();
1291                 try {
1292                     mImpl.setDisabledShowContextLocked(callingUid, flags);
1293                 } finally {
1294                     Binder.restoreCallingIdentity(caller);
1295                 }
1296             }
1297         }
1298 
1299         @Override
getDisabledShowContext()1300         public int getDisabledShowContext() {
1301             synchronized (this) {
1302                 if (mImpl == null) {
1303                     Slog.w(TAG, "getDisabledShowContext without running voice interaction service");
1304                     return 0;
1305                 }
1306                 final int callingUid = Binder.getCallingUid();
1307                 final long caller = Binder.clearCallingIdentity();
1308                 try {
1309                     return mImpl.getDisabledShowContextLocked(callingUid);
1310                 } finally {
1311                     Binder.restoreCallingIdentity(caller);
1312                 }
1313             }
1314         }
1315 
1316         @Override
getUserDisabledShowContext()1317         public int getUserDisabledShowContext() {
1318             synchronized (this) {
1319                 if (mImpl == null) {
1320                     Slog.w(TAG,
1321                             "getUserDisabledShowContext without running voice interaction service");
1322                     return 0;
1323                 }
1324                 final int callingUid = Binder.getCallingUid();
1325                 final long caller = Binder.clearCallingIdentity();
1326                 try {
1327                     return mImpl.getUserDisabledShowContextLocked(callingUid);
1328                 } finally {
1329                     Binder.restoreCallingIdentity(caller);
1330                 }
1331             }
1332         }
1333 
1334         @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
1335         @Override
setDisabled(boolean disabled)1336         public void setDisabled(boolean disabled) {
1337             super.setDisabled_enforcePermission();
1338 
1339             synchronized (this) {
1340                 if (mTemporarilyDisabled == disabled) {
1341                     if (DEBUG) Slog.d(TAG, "setDisabled(): already " + disabled);
1342                     return;
1343                 }
1344                 mTemporarilyDisabled = disabled;
1345                 if (mTemporarilyDisabled) {
1346                     Slog.i(TAG, "setDisabled(): temporarily disabling and hiding current session");
1347                     try {
1348                         hideCurrentSession();
1349                     } catch (RemoteException e) {
1350                         Log.w(TAG, "Failed to call hideCurrentSession", e);
1351                     }
1352                 } else {
1353                     Slog.i(TAG, "setDisabled(): re-enabling");
1354                 }
1355             }
1356         }
1357 
1358         @Override
startListeningVisibleActivityChanged(@onNull IBinder token)1359         public void startListeningVisibleActivityChanged(@NonNull IBinder token) {
1360             synchronized (this) {
1361                 if (mImpl == null) {
1362                     Slog.w(TAG, "startListeningVisibleActivityChanged without running"
1363                             + " voice interaction service");
1364                     return;
1365                 }
1366                 final long caller = Binder.clearCallingIdentity();
1367                 try {
1368                     mImpl.startListeningVisibleActivityChangedLocked(token);
1369                 } finally {
1370                     Binder.restoreCallingIdentity(caller);
1371                 }
1372             }
1373         }
1374 
1375         @Override
stopListeningVisibleActivityChanged(@onNull IBinder token)1376         public void stopListeningVisibleActivityChanged(@NonNull IBinder token) {
1377             synchronized (this) {
1378                 if (mImpl == null) {
1379                     Slog.w(TAG, "stopListeningVisibleActivityChanged without running"
1380                             + " voice interaction service");
1381                     return;
1382                 }
1383                 final long caller = Binder.clearCallingIdentity();
1384                 try {
1385                     mImpl.stopListeningVisibleActivityChangedLocked(token);
1386                 } finally {
1387                     Binder.restoreCallingIdentity(caller);
1388                 }
1389             }
1390         }
1391 
1392         @Override
notifyActivityEventChanged(@onNull IBinder activityToken, int type)1393         public void notifyActivityEventChanged(@NonNull IBinder activityToken, int type) {
1394             synchronized (this) {
1395                 if (mImpl == null || activityToken == null) {
1396                     return;
1397                 }
1398                 Binder.withCleanCallingIdentity(
1399                         () -> mImpl.notifyActivityEventChangedLocked(activityToken, type));
1400             }
1401         }
1402         //----------------- Hotword Detection/Validation APIs --------------------------------//
1403 
1404         @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION)
1405         @Override
updateState( @ullable PersistableBundle options, @Nullable SharedMemory sharedMemory, @NonNull IBinder token)1406         public void updateState(
1407                 @Nullable PersistableBundle options,
1408                 @Nullable SharedMemory sharedMemory,
1409                 @NonNull IBinder token) {
1410             super.updateState_enforcePermission();
1411 
1412             synchronized (this) {
1413                 enforceIsCurrentVoiceInteractionService();
1414 
1415                 Binder.withCleanCallingIdentity(
1416                         () -> mImpl.updateStateLocked(options, sharedMemory, token));
1417             }
1418         }
1419 
1420         @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION)
1421         @Override
initAndVerifyDetector( @onNull Identity voiceInteractorIdentity, @Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory, @NonNull IBinder token, IHotwordRecognitionStatusCallback callback, int detectorType)1422         public void initAndVerifyDetector(
1423                 @NonNull Identity voiceInteractorIdentity,
1424                 @Nullable PersistableBundle options,
1425                 @Nullable SharedMemory sharedMemory,
1426                 @NonNull IBinder token,
1427                 IHotwordRecognitionStatusCallback callback,
1428                 int detectorType) {
1429             super.initAndVerifyDetector_enforcePermission();
1430 
1431             synchronized (this) {
1432                 enforceIsCurrentVoiceInteractionService();
1433 
1434                 voiceInteractorIdentity.uid = Binder.getCallingUid();
1435                 voiceInteractorIdentity.pid = Binder.getCallingPid();
1436 
1437                 Binder.withCleanCallingIdentity(
1438                         () -> mImpl.initAndVerifyDetectorLocked(voiceInteractorIdentity, options,
1439                                 sharedMemory, token, callback, detectorType));
1440             }
1441         }
1442 
1443         @Override
destroyDetector(@onNull IBinder token)1444         public void destroyDetector(@NonNull IBinder token) {
1445             synchronized (this) {
1446                 if (mImpl == null) {
1447                     Slog.w(TAG, "destroyDetector without running voice interaction service");
1448                     return;
1449                 }
1450 
1451                 Binder.withCleanCallingIdentity(
1452                         () -> mImpl.destroyDetectorLocked(token));
1453             }
1454         }
1455 
1456         @Override
shutdownHotwordDetectionService()1457         public void shutdownHotwordDetectionService() {
1458             synchronized (this) {
1459                 enforceIsCurrentVoiceInteractionService();
1460 
1461                 if (mImpl == null) {
1462                     Slog.w(TAG,
1463                             "shutdownHotwordDetectionService without running voice"
1464                                     + " interaction service");
1465                     return;
1466                 }
1467                 final long caller = Binder.clearCallingIdentity();
1468                 try {
1469                     mImpl.shutdownHotwordDetectionServiceLocked();
1470                 } finally {
1471                     Binder.restoreCallingIdentity(caller);
1472                 }
1473             }
1474         }
1475 
1476         @android.annotation.EnforcePermission(
1477                 android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
1478         @Override
subscribeVisualQueryRecognitionStatus(IVisualQueryRecognitionStatusListener listener)1479         public void subscribeVisualQueryRecognitionStatus(IVisualQueryRecognitionStatusListener
1480                 listener) {
1481             super.subscribeVisualQueryRecognitionStatus_enforcePermission();
1482             synchronized (this) {
1483                 mVisualQueryRecognitionStatusListener = listener;
1484             }
1485         }
1486 
1487         @android.annotation.EnforcePermission(
1488                 android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
1489         @Override
enableVisualQueryDetection( IVisualQueryDetectionAttentionListener listener)1490         public void enableVisualQueryDetection(
1491                 IVisualQueryDetectionAttentionListener listener) {
1492             super.enableVisualQueryDetection_enforcePermission();
1493             synchronized (this) {
1494 
1495                 if (mImpl == null) {
1496                     Slog.w(TAG,
1497                             "enableVisualQueryDetection without running voice interaction service");
1498                     return;
1499                 }
1500                 this.mImpl.setVisualQueryDetectionAttentionListenerLocked(listener);
1501             }
1502         }
1503 
1504         @android.annotation.EnforcePermission(
1505                 android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
1506         @Override
disableVisualQueryDetection()1507         public void disableVisualQueryDetection() {
1508             super.disableVisualQueryDetection_enforcePermission();
1509             synchronized (this) {
1510                 if (mImpl == null) {
1511                     Slog.w(TAG,
1512                             "disableVisualQueryDetection without running voice interaction"
1513                                     + " service");
1514                     return;
1515                 }
1516                 this.mImpl.setVisualQueryDetectionAttentionListenerLocked(null);
1517             }
1518         }
1519 
1520         @Override
startPerceiving( IVisualQueryDetectionVoiceInteractionCallback callback)1521         public void startPerceiving(
1522                 IVisualQueryDetectionVoiceInteractionCallback callback)
1523                 throws RemoteException {
1524             enforceCallingPermission(Manifest.permission.RECORD_AUDIO);
1525             enforceCallingPermission(Manifest.permission.CAMERA);
1526             synchronized (this) {
1527                 enforceIsCurrentVoiceInteractionService();
1528 
1529                 if (mImpl == null) {
1530                     Slog.w(TAG, "startPerceiving without running voice interaction service");
1531                     return;
1532                 }
1533                 final long caller = Binder.clearCallingIdentity();
1534                 try {
1535                     boolean success = mImpl.startPerceivingLocked(callback);
1536                     if (success && mVisualQueryRecognitionStatusListener != null) {
1537                         mVisualQueryRecognitionStatusListener.onStartPerceiving();
1538                     }
1539                 } finally {
1540                     Binder.restoreCallingIdentity(caller);
1541                 }
1542             }
1543         }
1544 
1545         @Override
stopPerceiving()1546         public void stopPerceiving() throws RemoteException {
1547             synchronized (this) {
1548                 enforceIsCurrentVoiceInteractionService();
1549 
1550                 if (mImpl == null) {
1551                     Slog.w(TAG, "stopPerceiving without running voice interaction service");
1552                     return;
1553                 }
1554                 final long caller = Binder.clearCallingIdentity();
1555                 try {
1556                     boolean success = mImpl.stopPerceivingLocked();
1557                     if (success && mVisualQueryRecognitionStatusListener != null) {
1558                         mVisualQueryRecognitionStatusListener.onStopPerceiving();
1559                     }
1560                 } finally {
1561                     Binder.restoreCallingIdentity(caller);
1562                 }
1563             }
1564         }
1565 
1566         @Override
startListeningFromMic( AudioFormat audioFormat, IMicrophoneHotwordDetectionVoiceInteractionCallback callback)1567         public void startListeningFromMic(
1568                 AudioFormat audioFormat,
1569                 IMicrophoneHotwordDetectionVoiceInteractionCallback callback)
1570                 throws RemoteException {
1571             enforceCallingPermission(Manifest.permission.RECORD_AUDIO);
1572             enforceCallingPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD);
1573             synchronized (this) {
1574                 enforceIsCurrentVoiceInteractionService();
1575 
1576                 if (mImpl == null) {
1577                     Slog.w(TAG, "startListeningFromMic without running voice interaction service");
1578                     return;
1579                 }
1580                 final long caller = Binder.clearCallingIdentity();
1581                 try {
1582                     mImpl.startListeningFromMicLocked(audioFormat, callback);
1583                 } finally {
1584                     Binder.restoreCallingIdentity(caller);
1585                 }
1586             }
1587         }
1588 
1589         @Override
startListeningFromExternalSource( ParcelFileDescriptor audioStream, AudioFormat audioFormat, PersistableBundle options, @NonNull IBinder token, IMicrophoneHotwordDetectionVoiceInteractionCallback callback)1590         public void startListeningFromExternalSource(
1591                 ParcelFileDescriptor audioStream,
1592                 AudioFormat audioFormat,
1593                 PersistableBundle options,
1594                 @NonNull IBinder token,
1595                 IMicrophoneHotwordDetectionVoiceInteractionCallback callback)
1596                 throws RemoteException {
1597             synchronized (this) {
1598                 enforceIsCurrentVoiceInteractionService();
1599 
1600                 if (mImpl == null) {
1601                     Slog.w(TAG, "startListeningFromExternalSource without running voice"
1602                             + " interaction service");
1603                     return;
1604                 }
1605                 final long caller = Binder.clearCallingIdentity();
1606                 try {
1607                     mImpl.startListeningFromExternalSourceLocked(audioStream, audioFormat, options,
1608                             token, callback);
1609                 } finally {
1610                     Binder.restoreCallingIdentity(caller);
1611                 }
1612             }
1613         }
1614 
1615         @Override
stopListeningFromMic()1616         public void stopListeningFromMic() throws RemoteException {
1617             synchronized (this) {
1618                 enforceIsCurrentVoiceInteractionService();
1619 
1620                 if (mImpl == null) {
1621                     Slog.w(TAG, "stopListeningFromMic without running voice interaction service");
1622                     return;
1623                 }
1624                 final long caller = Binder.clearCallingIdentity();
1625                 try {
1626                     mImpl.stopListeningFromMicLocked();
1627                 } finally {
1628                     Binder.restoreCallingIdentity(caller);
1629                 }
1630             }
1631         }
1632 
1633         @Override
triggerHardwareRecognitionEventForTest( SoundTrigger.KeyphraseRecognitionEvent event, IHotwordRecognitionStatusCallback callback)1634         public void triggerHardwareRecognitionEventForTest(
1635                 SoundTrigger.KeyphraseRecognitionEvent event,
1636                 IHotwordRecognitionStatusCallback callback)
1637                 throws RemoteException {
1638             enforceCallingPermission(Manifest.permission.RECORD_AUDIO);
1639             enforceCallingPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD);
1640             synchronized (this) {
1641                 enforceIsCurrentVoiceInteractionService();
1642 
1643                 if (mImpl == null) {
1644                     Slog.w(TAG, "triggerHardwareRecognitionEventForTest without running"
1645                             + " voice interaction service");
1646                     return;
1647                 }
1648                 final long caller = Binder.clearCallingIdentity();
1649                 try {
1650                     mImpl.triggerHardwareRecognitionEventForTestLocked(event, callback);
1651                 } finally {
1652                     Binder.restoreCallingIdentity(caller);
1653                 }
1654             }
1655         }
1656 
1657 
1658       //----------------- Model management APIs --------------------------------//
1659 
1660         @Override
getKeyphraseSoundModel(int keyphraseId, String bcp47Locale)1661         public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
1662             enforceCallerAllowedToEnrollVoiceModel();
1663 
1664             if (bcp47Locale == null) {
1665                 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel");
1666             }
1667 
1668             final int callingUserId = UserHandle.getCallingUserId();
1669             final long caller = Binder.clearCallingIdentity();
1670             try {
1671                 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUserId, bcp47Locale);
1672             } finally {
1673                 Binder.restoreCallingIdentity(caller);
1674             }
1675         }
1676 
1677         @Override
updateKeyphraseSoundModel(KeyphraseSoundModel model)1678         public int updateKeyphraseSoundModel(KeyphraseSoundModel model) {
1679             enforceCallerAllowedToEnrollVoiceModel();
1680             if (model == null) {
1681                 throw new IllegalArgumentException("Model must not be null");
1682             }
1683 
1684             final long caller = Binder.clearCallingIdentity();
1685             try {
1686                 if (mDbHelper.updateKeyphraseSoundModel(model)) {
1687                     synchronized (this) {
1688                         // Notify the voice interaction service of a change in sound models.
1689                         if (mImpl != null && mImpl.mService != null) {
1690                             mImpl.notifySoundModelsChangedLocked();
1691                         }
1692                     }
1693                     return SoundTriggerInternal.STATUS_OK;
1694                 } else {
1695                     return SoundTriggerInternal.STATUS_ERROR;
1696                 }
1697             } finally {
1698                 Binder.restoreCallingIdentity(caller);
1699             }
1700         }
1701 
1702         @Override
deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale)1703         public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
1704             enforceCallerAllowedToEnrollVoiceModel();
1705 
1706             if (bcp47Locale == null) {
1707                 throw new IllegalArgumentException(
1708                         "Illegal argument(s) in deleteKeyphraseSoundModel");
1709             }
1710 
1711             final int callingUserId = UserHandle.getCallingUserId();
1712             boolean deleted = false;
1713             final long caller = Binder.clearCallingIdentity();
1714             try {
1715                 SoundTriggerSession session = mLoadedKeyphraseIds.get(keyphraseId);
1716                 if (session != null) {
1717                     int unloadStatus = session.unloadKeyphraseModel(keyphraseId);
1718                     if (unloadStatus != SoundTriggerInternal.STATUS_OK) {
1719                         Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus);
1720                     }
1721                 }
1722                 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUserId,
1723                         bcp47Locale);
1724                 return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR;
1725             } finally {
1726                 if (deleted) {
1727                     synchronized (this) {
1728                         // Notify the voice interaction service of a change in sound models.
1729                         if (mImpl != null && mImpl.mService != null) {
1730                             mImpl.notifySoundModelsChangedLocked();
1731                         }
1732                         mLoadedKeyphraseIds.remove(keyphraseId);
1733                     }
1734                 }
1735                 Binder.restoreCallingIdentity(caller);
1736             }
1737         }
1738 
1739         @Override
1740         @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_VOICE_KEYPHRASES)
setModelDatabaseForTestEnabled(boolean enabled, IBinder token)1741         public void setModelDatabaseForTestEnabled(boolean enabled, IBinder token) {
1742             super.setModelDatabaseForTestEnabled_enforcePermission();
1743             enforceCallerAllowedToEnrollVoiceModel();
1744             synchronized (this) {
1745                 if (enabled) {
1746                     // Replace the dbhelper with a new test db
1747                     final var db = new TestModelEnrollmentDatabase();
1748                     try {
1749                         // Listen to our caller death, and make sure we revert to the real
1750                         // db if they left the model in a test state.
1751                         token.linkToDeath(() -> {
1752                             synchronized (this) {
1753                                 if (mDbHelper == db) {
1754                                     mDbHelper = mRealDbHelper;
1755                                     mImpl.notifySoundModelsChangedLocked();
1756                                 }
1757                             }
1758                         }, 0);
1759                     } catch (RemoteException e) {
1760                         // If the caller is already dead, nothing to do.
1761                         return;
1762                     }
1763                     mDbHelper = db;
1764                     mImpl.notifySoundModelsChangedLocked();
1765                 } else {
1766                     // Nothing to do if the db is already set to the real impl.
1767                     if (mDbHelper != mRealDbHelper) {
1768                         mDbHelper = mRealDbHelper;
1769                         mImpl.notifySoundModelsChangedLocked();
1770                     }
1771                 }
1772             }
1773         }
1774 
1775         //----------------- SoundTrigger APIs --------------------------------//
1776         @Override
isEnrolledForKeyphrase(int keyphraseId, String bcp47Locale)1777         public boolean isEnrolledForKeyphrase(int keyphraseId, String bcp47Locale) {
1778             synchronized (this) {
1779                 enforceIsCurrentVoiceInteractionService();
1780             }
1781 
1782             if (bcp47Locale == null) {
1783                 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase");
1784             }
1785 
1786             final int callingUserId = UserHandle.getCallingUserId();
1787             final long caller = Binder.clearCallingIdentity();
1788             try {
1789                 KeyphraseSoundModel model =
1790                         mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUserId, bcp47Locale);
1791                 return model != null;
1792             } finally {
1793                 Binder.restoreCallingIdentity(caller);
1794             }
1795         }
1796 
1797         @Nullable
getEnrolledKeyphraseMetadata(String keyphrase, String bcp47Locale)1798         public KeyphraseMetadata getEnrolledKeyphraseMetadata(String keyphrase,
1799                 String bcp47Locale) {
1800             synchronized (this) {
1801                 enforceIsCurrentVoiceInteractionService();
1802             }
1803 
1804             if (bcp47Locale == null) {
1805                 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase");
1806             }
1807 
1808             final int callingUserId = UserHandle.getCallingUserId();
1809             final long caller = Binder.clearCallingIdentity();
1810             try {
1811                 KeyphraseSoundModel model =
1812                         mDbHelper.getKeyphraseSoundModel(keyphrase, callingUserId, bcp47Locale);
1813                 if (model == null) {
1814                     return null;
1815                 }
1816 
1817                 for (SoundTrigger.Keyphrase phrase : model.getKeyphrases()) {
1818                     if (keyphrase.equals(phrase.getText())) {
1819                         ArraySet<Locale> locales = new ArraySet<>();
1820                         locales.add(phrase.getLocale());
1821                         return new KeyphraseMetadata(
1822                                 phrase.getId(),
1823                                 phrase.getText(),
1824                                 locales,
1825                                 phrase.getRecognitionModes());
1826                     }
1827                 }
1828             } finally {
1829                 Binder.restoreCallingIdentity(caller);
1830             }
1831 
1832             return null;
1833         }
1834 
1835         private class SoundTriggerSession extends IVoiceInteractionSoundTriggerSession.Stub {
1836             final SoundTriggerInternal.Session mSession;
1837             private IHotwordRecognitionStatusCallback mSessionExternalCallback;
1838             private IRecognitionStatusCallback mSessionInternalCallback;
1839             private final Identity mVoiceInteractorIdentity;
1840 
SoundTriggerSession( SoundTriggerInternal.Session session, Identity voiceInteractorIdentity)1841             SoundTriggerSession(
1842                     SoundTriggerInternal.Session session,
1843                     Identity voiceInteractorIdentity) {
1844                 mSession = session;
1845                 mVoiceInteractorIdentity = voiceInteractorIdentity;
1846             }
1847 
1848             @Override
getDspModuleProperties()1849             public ModuleProperties getDspModuleProperties() {
1850                 // Allow the call if this is the current voice interaction service.
1851                 synchronized (VoiceInteractionManagerServiceStub.this) {
1852                     enforceIsCurrentVoiceInteractionService();
1853 
1854                     final long caller = Binder.clearCallingIdentity();
1855                     try {
1856                         return mSession.getModuleProperties();
1857                     } finally {
1858                         Binder.restoreCallingIdentity(caller);
1859                     }
1860                 }
1861             }
1862 
1863             @Override
startRecognition(int keyphraseId, String bcp47Locale, IHotwordRecognitionStatusCallback callback, RecognitionConfig recognitionConfig, boolean runInBatterySaverMode)1864             public int startRecognition(int keyphraseId, String bcp47Locale,
1865                     IHotwordRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
1866                     boolean runInBatterySaverMode) {
1867                 // Allow the call if this is the current voice interaction service.
1868                 synchronized (VoiceInteractionManagerServiceStub.this) {
1869                     enforceIsCurrentVoiceInteractionService();
1870 
1871                     if (callback == null || recognitionConfig == null || bcp47Locale == null) {
1872                         throw new IllegalArgumentException(
1873                                 "Illegal argument(s) in startRecognition");
1874                     }
1875                     if (runInBatterySaverMode) {
1876                         enforceCallingPermission(
1877                                 Manifest.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER);
1878                     }
1879                 }
1880 
1881                 final int callingUserId = UserHandle.getCallingUserId();
1882                 final long caller = Binder.clearCallingIdentity();
1883                 try {
1884                     KeyphraseSoundModel soundModel =
1885                             mDbHelper.getKeyphraseSoundModel(keyphraseId,
1886                                     callingUserId, bcp47Locale);
1887                     if (soundModel == null
1888                             || soundModel.getUuid() == null
1889                             || soundModel.getKeyphrases() == null) {
1890                         Slog.w(TAG, "No matching sound model found in startRecognition");
1891                         return SoundTriggerInternal.STATUS_ERROR;
1892                     }
1893                     // Regardless of the status of the start recognition, we need to make sure
1894                     // that we unload this model if needed later.
1895                     synchronized (VoiceInteractionManagerServiceStub.this) {
1896                         mLoadedKeyphraseIds.put(keyphraseId, this);
1897                         if (mSessionExternalCallback == null
1898                                 || mSessionInternalCallback == null
1899                                 || callback.asBinder() != mSessionExternalCallback.asBinder()) {
1900                             mSessionInternalCallback = createSoundTriggerCallbackLocked(callback,
1901                                     mVoiceInteractorIdentity);
1902                             mSessionExternalCallback = callback;
1903                         }
1904                     }
1905                     return mSession.startRecognition(keyphraseId, soundModel,
1906                             mSessionInternalCallback, recognitionConfig, runInBatterySaverMode);
1907                 } finally {
1908                     Binder.restoreCallingIdentity(caller);
1909                 }
1910             }
1911 
1912             @Override
stopRecognition(int keyphraseId, IHotwordRecognitionStatusCallback callback)1913             public int stopRecognition(int keyphraseId,
1914                     IHotwordRecognitionStatusCallback callback) {
1915                 final IRecognitionStatusCallback soundTriggerCallback;
1916                 // Allow the call if this is the current voice interaction service.
1917                 synchronized (VoiceInteractionManagerServiceStub.this) {
1918                     enforceIsCurrentVoiceInteractionService();
1919                     if (mSessionExternalCallback == null
1920                             || mSessionInternalCallback == null
1921                             || callback.asBinder() != mSessionExternalCallback.asBinder()) {
1922                         soundTriggerCallback = createSoundTriggerCallbackLocked(callback,
1923                                 mVoiceInteractorIdentity);
1924                         Slog.w(TAG, "stopRecognition() called with a different callback than"
1925                                 + "startRecognition()");
1926                     } else {
1927                         soundTriggerCallback = mSessionInternalCallback;
1928                     }
1929                     mSessionExternalCallback = null;
1930                     mSessionInternalCallback = null;
1931                 }
1932 
1933                 final long caller = Binder.clearCallingIdentity();
1934                 try {
1935                     return mSession.stopRecognition(keyphraseId, soundTriggerCallback);
1936                 } finally {
1937                     Binder.restoreCallingIdentity(caller);
1938                 }
1939             }
1940 
1941             @Override
setParameter(int keyphraseId, @ModelParams int modelParam, int value)1942             public int setParameter(int keyphraseId, @ModelParams int modelParam, int value) {
1943                 // Allow the call if this is the current voice interaction service.
1944                 synchronized (VoiceInteractionManagerServiceStub.this) {
1945                     enforceIsCurrentVoiceInteractionService();
1946                 }
1947 
1948                 final long caller = Binder.clearCallingIdentity();
1949                 try {
1950                     return mSession.setParameter(keyphraseId, modelParam, value);
1951                 } finally {
1952                     Binder.restoreCallingIdentity(caller);
1953                 }
1954             }
1955 
1956             @Override
getParameter(int keyphraseId, @ModelParams int modelParam)1957             public int getParameter(int keyphraseId, @ModelParams int modelParam) {
1958                 // Allow the call if this is the current voice interaction service.
1959                 synchronized (VoiceInteractionManagerServiceStub.this) {
1960                     enforceIsCurrentVoiceInteractionService();
1961                 }
1962 
1963                 final long caller = Binder.clearCallingIdentity();
1964                 try {
1965                     return mSession.getParameter(keyphraseId, modelParam);
1966                 } finally {
1967                     Binder.restoreCallingIdentity(caller);
1968                 }
1969             }
1970 
1971             @Override
1972             @Nullable
queryParameter(int keyphraseId, @ModelParams int modelParam)1973             public ModelParamRange queryParameter(int keyphraseId, @ModelParams int modelParam) {
1974                 // Allow the call if this is the current voice interaction service.
1975                 synchronized (VoiceInteractionManagerServiceStub.this) {
1976                     enforceIsCurrentVoiceInteractionService();
1977                 }
1978 
1979                 final long caller = Binder.clearCallingIdentity();
1980                 try {
1981                     return mSession.queryParameter(keyphraseId, modelParam);
1982                 } finally {
1983                     Binder.restoreCallingIdentity(caller);
1984                 }
1985             }
1986 
1987             @Override
detach()1988             public void detach() {
1989                 mSession.detach();
1990             }
1991 
unloadKeyphraseModel(int keyphraseId)1992             private int unloadKeyphraseModel(int keyphraseId) {
1993                 final long caller = Binder.clearCallingIdentity();
1994                 try {
1995                     return mSession.unloadKeyphraseModel(keyphraseId);
1996                 } finally {
1997                     Binder.restoreCallingIdentity(caller);
1998                 }
1999             }
2000         }
2001 
unloadAllKeyphraseModels()2002         private synchronized void unloadAllKeyphraseModels() {
2003             for (int i = 0; i < mLoadedKeyphraseIds.size(); i++) {
2004                 int id = mLoadedKeyphraseIds.keyAt(i);
2005                 SoundTriggerSession session = mLoadedKeyphraseIds.valueAt(i);
2006                 int status = session.unloadKeyphraseModel(id);
2007                 if (status != SoundTriggerInternal.STATUS_OK) {
2008                     Slog.w(TAG, "Failed to unload keyphrase " + id + ":" + status);
2009                 }
2010             }
2011             mLoadedKeyphraseIds.clear();
2012         }
2013 
2014         @Override
getActiveServiceComponentName()2015         public ComponentName getActiveServiceComponentName() {
2016             synchronized (this) {
2017                 return mImpl != null ? mImpl.mComponent : null;
2018             }
2019         }
2020 
2021         @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
2022         @Override
showSessionForActiveService(@ullable Bundle args, int sourceFlags, @Nullable String attributionTag, @Nullable IVoiceInteractionSessionShowCallback showCallback, @Nullable IBinder activityToken)2023         public boolean showSessionForActiveService(@Nullable Bundle args, int sourceFlags,
2024                 @Nullable String attributionTag,
2025                 @Nullable IVoiceInteractionSessionShowCallback showCallback,
2026                 @Nullable IBinder activityToken) {
2027             super.showSessionForActiveService_enforcePermission();
2028 
2029             if (DEBUG_USER) Slog.d(TAG, "showSessionForActiveService()");
2030 
2031             synchronized (this) {
2032                 if (mImpl == null) {
2033                     Slog.w(TAG, "showSessionForActiveService without running voice interaction"
2034                             + "service");
2035                     return false;
2036                 }
2037                 if (mTemporarilyDisabled) {
2038                     Slog.i(TAG, "showSessionForActiveService(): ignored while temporarily "
2039                             + "disabled");
2040                     return false;
2041                 }
2042 
2043                 final long caller = Binder.clearCallingIdentity();
2044                 try {
2045                     // HotwordDetector trigger uses VoiceInteractionService#showSession
2046                     // We need to cancel here because UI is not being shown due to a SoundTrigger
2047                     // HAL event.
2048                     HotwordMetricsLogger.cancelHotwordTriggerToUiLatencySession(mContext);
2049 
2050                     return mImpl.showSessionLocked(args,
2051                             sourceFlags
2052                                     | VoiceInteractionSession.SHOW_WITH_ASSIST
2053                                     | VoiceInteractionSession.SHOW_WITH_SCREENSHOT,
2054                             attributionTag, showCallback, activityToken);
2055                 } finally {
2056                     Binder.restoreCallingIdentity(caller);
2057                 }
2058             }
2059         }
2060 
2061         @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
2062         @Override
hideCurrentSession()2063         public void hideCurrentSession() throws RemoteException {
2064 
2065             super.hideCurrentSession_enforcePermission();
2066 
2067             if (mImpl == null) {
2068                 return;
2069             }
2070             final long caller = Binder.clearCallingIdentity();
2071             try {
2072                 if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) {
2073                     try {
2074                         mImpl.mActiveSession.mSession.closeSystemDialogs();
2075                     } catch (RemoteException e) {
2076                         Log.w(TAG, "Failed to call closeSystemDialogs", e);
2077                     }
2078                 }
2079             } finally {
2080                 Binder.restoreCallingIdentity(caller);
2081             }
2082         }
2083 
2084         @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
2085         @Override
launchVoiceAssistFromKeyguard()2086         public void launchVoiceAssistFromKeyguard() {
2087             super.launchVoiceAssistFromKeyguard_enforcePermission();
2088 
2089             synchronized (this) {
2090                 if (mImpl == null) {
2091                     Slog.w(TAG, "launchVoiceAssistFromKeyguard without running voice interaction"
2092                             + "service");
2093                     return;
2094                 }
2095                 final long caller = Binder.clearCallingIdentity();
2096                 try {
2097                     mImpl.launchVoiceAssistFromKeyguard();
2098                 } finally {
2099                     Binder.restoreCallingIdentity(caller);
2100                 }
2101             }
2102         }
2103 
2104         @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
2105         @Override
isSessionRunning()2106         public boolean isSessionRunning() {
2107             super.isSessionRunning_enforcePermission();
2108 
2109             synchronized (this) {
2110                 return mImpl != null && mImpl.mActiveSession != null;
2111             }
2112         }
2113 
2114         @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
2115         @Override
activeServiceSupportsAssist()2116         public boolean activeServiceSupportsAssist() {
2117             super.activeServiceSupportsAssist_enforcePermission();
2118 
2119             synchronized (this) {
2120                 return mImpl != null && mImpl.mInfo != null && mImpl.mInfo.getSupportsAssist();
2121             }
2122         }
2123 
2124         @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
2125         @Override
activeServiceSupportsLaunchFromKeyguard()2126         public boolean activeServiceSupportsLaunchFromKeyguard() throws RemoteException {
2127             super.activeServiceSupportsLaunchFromKeyguard_enforcePermission();
2128 
2129             synchronized (this) {
2130                 return mImpl != null && mImpl.mInfo != null
2131                         && mImpl.mInfo.getSupportsLaunchFromKeyguard();
2132             }
2133         }
2134 
2135         @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
2136         @Override
onLockscreenShown()2137         public void onLockscreenShown() {
2138             super.onLockscreenShown_enforcePermission();
2139 
2140             synchronized (this) {
2141                 if (mImpl == null) {
2142                     return;
2143                 }
2144                 final long caller = Binder.clearCallingIdentity();
2145                 try {
2146                     if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) {
2147                         try {
2148                             mImpl.mActiveSession.mSession.onLockscreenShown();
2149                         } catch (RemoteException e) {
2150                             Log.w(TAG, "Failed to call onLockscreenShown", e);
2151                         }
2152                     }
2153                 } finally {
2154                     Binder.restoreCallingIdentity(caller);
2155                 }
2156             }
2157         }
2158 
2159         @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
2160         @Override
registerVoiceInteractionSessionListener( IVoiceInteractionSessionListener listener)2161         public void registerVoiceInteractionSessionListener(
2162                 IVoiceInteractionSessionListener listener) {
2163             super.registerVoiceInteractionSessionListener_enforcePermission();
2164 
2165             synchronized (this) {
2166                 mVoiceInteractionSessionListeners.register(listener);
2167             }
2168         }
2169 
2170         @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
2171         @Override
getActiveServiceSupportedActions(List<String> voiceActions, IVoiceActionCheckCallback callback)2172         public void getActiveServiceSupportedActions(List<String> voiceActions,
2173                 IVoiceActionCheckCallback callback) {
2174             super.getActiveServiceSupportedActions_enforcePermission();
2175 
2176             synchronized (this) {
2177                 if (mImpl == null) {
2178                     try {
2179                         callback.onComplete(null);
2180                     } catch (RemoteException e) {
2181                     }
2182                     return;
2183                 }
2184                 final long caller = Binder.clearCallingIdentity();
2185                 try {
2186                     mImpl.getActiveServiceSupportedActions(voiceActions, callback);
2187                 } finally {
2188                     Binder.restoreCallingIdentity(caller);
2189                 }
2190             }
2191         }
2192 
onSessionShown()2193         public void onSessionShown() {
2194             synchronized (this) {
2195                 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
2196                 for (int i = 0; i < size; ++i) {
2197                     final IVoiceInteractionSessionListener listener =
2198                             mVoiceInteractionSessionListeners.getBroadcastItem(i);
2199                     try {
2200                         listener.onVoiceSessionShown();
2201                     } catch (RemoteException e) {
2202                         Slog.e(TAG, "Error delivering voice interaction open event.", e);
2203                     }
2204                 }
2205                 mVoiceInteractionSessionListeners.finishBroadcast();
2206             }
2207         }
2208 
onSessionHidden()2209         public void onSessionHidden() {
2210             synchronized (this) {
2211                 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
2212                 for (int i = 0; i < size; ++i) {
2213                     final IVoiceInteractionSessionListener listener =
2214                             mVoiceInteractionSessionListeners.getBroadcastItem(i);
2215                     try {
2216                         listener.onVoiceSessionHidden();
2217 
2218                     } catch (RemoteException e) {
2219                         Slog.e(TAG, "Error delivering voice interaction closed event.", e);
2220                     }
2221                 }
2222                 mVoiceInteractionSessionListeners.finishBroadcast();
2223             }
2224         }
2225 
setSessionWindowVisible(IBinder token, boolean visible)2226         public void setSessionWindowVisible(IBinder token, boolean visible) {
2227             synchronized (this) {
2228                 if (mImpl == null) {
2229                     Slog.w(TAG, "setSessionWindowVisible called without running voice interaction "
2230                             + "service");
2231                     return;
2232                 }
2233                 if (mImpl.mActiveSession == null || token != mImpl.mActiveSession.mToken) {
2234                     Slog.w(TAG, "setSessionWindowVisible does not match active session");
2235                     return;
2236                 }
2237                 final long caller = Binder.clearCallingIdentity();
2238                 try {
2239                     mVoiceInteractionSessionListeners.broadcast(listener -> {
2240                         try {
2241                             listener.onVoiceSessionWindowVisibilityChanged(visible);
2242                         } catch (RemoteException e) {
2243                             Slog.e(TAG, "Error delivering window visibility event to listener.", e);
2244                         }
2245                     });
2246                 } finally {
2247                     Binder.restoreCallingIdentity(caller);
2248                 }
2249             }
2250         }
2251 
getAccessibilityDetectionEnabled()2252         public boolean getAccessibilityDetectionEnabled() {
2253             synchronized (this) {
2254                 if (mImpl == null) {
2255                     Slog.w(TAG, "registerAccessibilityDetectionSettingsListener called without"
2256                             + " running voice interaction service");
2257                     return false;
2258                 }
2259                 return mImpl.getAccessibilityDetectionEnabled();
2260             }
2261         }
2262 
2263         @Override
registerAccessibilityDetectionSettingsListener( IVoiceInteractionAccessibilitySettingsListener listener)2264         public void registerAccessibilityDetectionSettingsListener(
2265                 IVoiceInteractionAccessibilitySettingsListener listener) {
2266             synchronized (this) {
2267                 if (mImpl == null) {
2268                     Slog.w(TAG, "registerAccessibilityDetectionSettingsListener called without"
2269                             + " running voice interaction service");
2270                     return;
2271                 }
2272                 mImpl.registerAccessibilityDetectionSettingsListenerLocked(listener);
2273             }
2274         }
2275 
2276         @Override
unregisterAccessibilityDetectionSettingsListener( IVoiceInteractionAccessibilitySettingsListener listener)2277         public void unregisterAccessibilityDetectionSettingsListener(
2278                 IVoiceInteractionAccessibilitySettingsListener listener) {
2279             synchronized (this) {
2280                 if (mImpl == null) {
2281                     Slog.w(TAG, "unregisterAccessibilityDetectionSettingsListener called "
2282                             + "without running voice interaction service");
2283                     return;
2284                 }
2285                 mImpl.unregisterAccessibilityDetectionSettingsListenerLocked(listener);
2286             }
2287         }
2288 
2289 
2290         @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2291         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2292             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
2293             synchronized (this) {
2294                 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)");
2295                 pw.println("  mEnableService: " + mEnableService);
2296                 pw.println("  mTemporarilyDisabled: " + mTemporarilyDisabled);
2297                 pw.println("  mCurUser: " + mCurUser);
2298                 pw.println("  mCurUserSupported: " + mCurUserSupported);
2299                 pw.println("  mIsHdsRequired: " + IS_HDS_REQUIRED);
2300                 dumpSupportedUsers(pw, "  ");
2301                 mDbHelper.dump(pw);
2302                 if (mImpl == null) {
2303                     pw.println("  (No active implementation)");
2304                 } else {
2305                     mImpl.dumpLocked(fd, pw, args);
2306                 }
2307             }
2308         }
2309 
2310         @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)2311         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
2312                 String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
2313             new VoiceInteractionManagerServiceShellCommand(mServiceStub)
2314                     .exec(this, in, out, err, args, callback, resultReceiver);
2315         }
2316 
2317         @Override
setUiHints(Bundle hints)2318         public void setUiHints(Bundle hints) {
2319             synchronized (this) {
2320                 enforceIsCurrentVoiceInteractionService();
2321 
2322                 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
2323                 for (int i = 0; i < size; ++i) {
2324                     final IVoiceInteractionSessionListener listener =
2325                             mVoiceInteractionSessionListeners.getBroadcastItem(i);
2326                     try {
2327                         listener.onSetUiHints(hints);
2328                     } catch (RemoteException e) {
2329                         Slog.e(TAG, "Error delivering UI hints.", e);
2330                     }
2331                 }
2332                 mVoiceInteractionSessionListeners.finishBroadcast();
2333             }
2334         }
2335 
isCallerHoldingPermission(String permission)2336         private boolean isCallerHoldingPermission(String permission) {
2337             return mContext.checkCallingOrSelfPermission(permission)
2338                     == PackageManager.PERMISSION_GRANTED;
2339         }
2340 
enforceCallingPermission(String permission)2341         private void enforceCallingPermission(String permission) {
2342             if (!isCallerHoldingPermission(permission)) {
2343                 throw new SecurityException("Caller does not hold the permission " + permission);
2344             }
2345         }
2346 
enforceIsCurrentVoiceInteractionService()2347         private void enforceIsCurrentVoiceInteractionService() {
2348             if (!isCallerCurrentVoiceInteractionService()) {
2349                 throw new
2350                     SecurityException("Caller is not the current voice interaction service");
2351             }
2352         }
2353 
enforceIsCallerPreinstalledAssistant()2354         private void enforceIsCallerPreinstalledAssistant() {
2355             if (!isCallerPreinstalledAssistant()) {
2356                 throw new
2357                         SecurityException("Caller is not the pre-installed assistant.");
2358             }
2359         }
2360 
enforceCallerAllowedToEnrollVoiceModel()2361         private void enforceCallerAllowedToEnrollVoiceModel() {
2362             if (isCallerHoldingPermission(Manifest.permission.KEYPHRASE_ENROLLMENT_APPLICATION)) {
2363                 return;
2364             }
2365 
2366             enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
2367             enforceIsCurrentVoiceInteractionService();
2368         }
2369 
isCallerCurrentVoiceInteractionService()2370         private boolean isCallerCurrentVoiceInteractionService() {
2371             return mImpl != null
2372                     && mImpl.mInfo.getServiceInfo().applicationInfo.uid == Binder.getCallingUid();
2373         }
2374 
isCallerPreinstalledAssistant()2375         private boolean isCallerPreinstalledAssistant() {
2376             return mImpl != null
2377                     && mImpl.getApplicationInfo().uid == Binder.getCallingUid()
2378                     && (mImpl.getApplicationInfo().isSystemApp()
2379                     || mImpl.getApplicationInfo().isUpdatedSystemApp());
2380         }
2381 
setImplLocked(VoiceInteractionManagerServiceImpl impl)2382         private void setImplLocked(VoiceInteractionManagerServiceImpl impl) {
2383             mImpl = impl;
2384             mAtmInternal.notifyActiveVoiceInteractionServiceChanged(
2385                     getActiveServiceComponentName());
2386         }
2387 
createSoundTriggerCallbackLocked( IHotwordRecognitionStatusCallback callback, Identity voiceInteractorIdentity)2388         private IRecognitionStatusCallback createSoundTriggerCallbackLocked(
2389                 IHotwordRecognitionStatusCallback callback,
2390                 Identity voiceInteractorIdentity) {
2391             if (mImpl == null) {
2392                 return null;
2393             }
2394             return mImpl.createSoundTriggerCallbackLocked(mContext, callback,
2395                     voiceInteractorIdentity);
2396         }
2397 
2398         class RoleObserver implements OnRoleHoldersChangedListener {
2399             private PackageManager mPm = mContext.getPackageManager();
2400             private RoleManager mRm = mContext.getSystemService(RoleManager.class);
2401 
RoleObserver(@onNull @allbackExecutor Executor executor)2402             RoleObserver(@NonNull @CallbackExecutor Executor executor) {
2403                 mRm.addOnRoleHoldersChangedListenerAsUser(executor, this, UserHandle.ALL);
2404                 // Sync only if assistant role has been initialized.
2405                 if (mRm.isRoleAvailable(RoleManager.ROLE_ASSISTANT)) {
2406                     UserHandle currentUser = UserHandle.of(LocalServices.getService(
2407                             ActivityManagerInternal.class).getCurrentUserId());
2408                     onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT, currentUser);
2409                 }
2410             }
2411 
2412             /**
2413              * Convert the assistant-role holder into settings. The rest of the system uses the
2414              * settings.
2415              *
2416              * @param roleName the name of the role whose holders are changed
2417              * @param user the user for this role holder change
2418              */
2419             @Override
onRoleHoldersChanged(@onNull String roleName, @NonNull UserHandle user)2420             public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
2421                 if (!roleName.equals(RoleManager.ROLE_ASSISTANT)) {
2422                     return;
2423                 }
2424 
2425                 List<String> roleHolders = mRm.getRoleHoldersAsUser(roleName, user);
2426 
2427                 if (DEBUG) {
2428                     Slogf.d(TAG, "onRoleHoldersChanged(%s, %s): roleHolders=%s", roleName, user,
2429                             roleHolders);
2430                 }
2431 
2432                 // TODO(b/226201975): this method is beling called when a pre-created user is added,
2433                 // at which point it doesn't have any role holders. But it's not called again when
2434                 // the actual user is added (i.e., when the  pre-created user is converted), so we
2435                 // need to save the user id and call this method again when it's converted
2436                 // (at onPreCreatedUserConversion()).
2437                 // Once RoleService properly handles pre-created users, this workaround should be
2438                 // removed.
2439                 if (roleHolders.isEmpty()) {
2440                     UserInfo userInfo = mUserManagerInternal.getUserInfo(user.getIdentifier());
2441                     if (userInfo != null && userInfo.preCreated) {
2442                         Slogf.d(TAG, "onRoleHoldersChanged(): ignoring pre-created user %s for now,"
2443                                 + " this method will be called again when it's converted to a real"
2444                                 + " user", userInfo.toFullString());
2445                         return;
2446                     }
2447                 }
2448 
2449                 int userId = user.getIdentifier();
2450                 if (roleHolders.isEmpty()) {
2451                     Settings.Secure.putStringForUser(getContext().getContentResolver(),
2452                             Settings.Secure.ASSISTANT, "", userId);
2453                     Settings.Secure.putStringForUser(getContext().getContentResolver(),
2454                             Settings.Secure.VOICE_INTERACTION_SERVICE, "", userId);
2455                 } else {
2456                     // Assistant is singleton role
2457                     String pkg = roleHolders.get(0);
2458 
2459                     // Try to set role holder as VoiceInteractionService
2460                     for (ResolveInfo resolveInfo : queryInteractorServices(userId, pkg)) {
2461                         ServiceInfo serviceInfo = resolveInfo.serviceInfo;
2462 
2463                         VoiceInteractionServiceInfo voiceInteractionServiceInfo =
2464                                 new VoiceInteractionServiceInfo(mPm, serviceInfo);
2465                         if (!voiceInteractionServiceInfo.getSupportsAssist()) {
2466                             continue;
2467                         }
2468 
2469                         String serviceComponentName = serviceInfo.getComponentName()
2470                                 .flattenToShortString();
2471                         if (voiceInteractionServiceInfo.getRecognitionService() == null) {
2472                             Slog.e(TAG, "The RecognitionService must be set to avoid boot "
2473                                     + "loop on earlier platform version. Also make sure that this "
2474                                     + "is a valid RecognitionService when running on Android 11 "
2475                                     + "or earlier.");
2476                             serviceComponentName = "";
2477                         }
2478 
2479                         Settings.Secure.putStringForUser(getContext().getContentResolver(),
2480                                 Settings.Secure.ASSISTANT, serviceComponentName, userId);
2481                         Settings.Secure.putStringForUser(getContext().getContentResolver(),
2482                                 Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName,
2483                                 userId);
2484                         return;
2485                     }
2486 
2487                     // If no service could be found try to set assist activity
2488                     final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser(
2489                             new Intent(Intent.ACTION_ASSIST).setPackage(pkg),
2490                             PackageManager.MATCH_DEFAULT_ONLY
2491                                     | PackageManager.MATCH_DIRECT_BOOT_AWARE
2492                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
2493 
2494                     for (ResolveInfo resolveInfo : activities) {
2495                         ActivityInfo activityInfo = resolveInfo.activityInfo;
2496 
2497                         Settings.Secure.putStringForUser(getContext().getContentResolver(),
2498                                 Settings.Secure.ASSISTANT,
2499                                 activityInfo.getComponentName().flattenToShortString(), userId);
2500                         Settings.Secure.putStringForUser(getContext().getContentResolver(),
2501                                 Settings.Secure.VOICE_INTERACTION_SERVICE, "", userId);
2502                         return;
2503                     }
2504                 }
2505             }
2506         }
2507 
2508         class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler)2509             SettingsObserver(Handler handler) {
2510                 super(handler);
2511                 ContentResolver resolver = mContext.getContentResolver();
2512                 resolver.registerContentObserver(Settings.Secure.getUriFor(
2513                         Settings.Secure.VOICE_INTERACTION_SERVICE), false, this,
2514                         UserHandle.USER_ALL);
2515             }
2516 
2517             @Override
onChange(boolean selfChange)2518             public void onChange(boolean selfChange) {
2519                 synchronized (VoiceInteractionManagerServiceStub.this) {
2520                     switchImplementationIfNeededLocked(false);
2521                 }
2522             }
2523         }
2524 
resetServicesIfNoRecognitionService(ComponentName serviceComponent, int userHandle)2525         private void resetServicesIfNoRecognitionService(ComponentName serviceComponent,
2526                 int userHandle) {
2527             for (ResolveInfo resolveInfo : queryInteractorServices(userHandle,
2528                     serviceComponent.getPackageName())) {
2529                 VoiceInteractionServiceInfo serviceInfo =
2530                         new VoiceInteractionServiceInfo(
2531                                 mContext.getPackageManager(),
2532                                 resolveInfo.serviceInfo);
2533                 if (!serviceInfo.getSupportsAssist()) {
2534                     continue;
2535                 }
2536                 if (serviceInfo.getRecognitionService() == null) {
2537                     Slog.e(TAG, "The RecognitionService must be set to "
2538                             + "avoid boot loop on earlier platform version. "
2539                             + "Also make sure that this is a valid "
2540                             + "RecognitionService when running on Android 11 "
2541                             + "or earlier.");
2542                     setCurInteractor(null, userHandle);
2543                     resetCurAssistant(userHandle);
2544                 }
2545             }
2546         }
2547 
2548         PackageMonitor mPackageMonitor = new PackageMonitor(
2549                 /* supportsPackageRestartQuery= */ true) {
2550 
2551             @Override
2552             public boolean onHandleForceStop(Intent intent, String[] packages, int uid,
2553                     boolean doit) {
2554                 if (DEBUG) Slog.d(TAG, "onHandleForceStop uid=" + uid + " doit=" + doit);
2555 
2556                 int userHandle = UserHandle.getUserId(uid);
2557                 ComponentName curInteractor = getCurInteractor(userHandle);
2558                 ComponentName curRecognizer = getCurRecognizer(userHandle);
2559                 boolean hitInt = false;
2560                 boolean hitRec = false;
2561                 for (String pkg : packages) {
2562                     if (curInteractor != null && pkg.equals(curInteractor.getPackageName())) {
2563                         hitInt = true;
2564                         break;
2565                     } else if (curRecognizer != null
2566                             && pkg.equals(curRecognizer.getPackageName())) {
2567                         hitRec = true;
2568                         break;
2569                     }
2570                 }
2571                 if (hitInt && doit) {
2572                     // The user is force stopping our current interactor, restart the service.
2573                     synchronized (VoiceInteractionManagerServiceStub.this) {
2574                         Slog.i(TAG, "Force stopping current voice interactor: "
2575                                 + getCurInteractor(userHandle));
2576                         unloadAllKeyphraseModels();
2577                         if (mImpl != null) {
2578                             mImpl.shutdownLocked();
2579                             setImplLocked(null);
2580                         }
2581                         switchImplementationIfNeededLocked(true);
2582                     }
2583                 } else if (hitRec && doit) {
2584                     // We are just force-stopping the current recognizer, which is not
2585                     // also the current interactor.
2586                     synchronized (VoiceInteractionManagerServiceStub.this) {
2587                         Slog.i(TAG, "Force stopping current voice recognizer: "
2588                                 + getCurRecognizer(userHandle));
2589                         initRecognizer(userHandle);
2590                     }
2591                 }
2592                 return hitInt || hitRec;
2593             }
2594 
2595             @Override
2596             public void onPackageModified(@NonNull String pkgName) {
2597                 // If the package modified is not in the current user, then don't bother making
2598                 // any changes as we are going to do any initialization needed when we switch users.
2599                 if (mCurUser != getChangingUserId()) {
2600                     return;
2601                 }
2602                 // Package getting updated will be handled by {@link #onSomePackagesChanged}.
2603                 if (isPackageAppearing(pkgName) != PACKAGE_UNCHANGED) {
2604                     return;
2605                 }
2606                 if (getCurRecognizer(mCurUser) == null) {
2607                     initRecognizer(mCurUser);
2608                 }
2609                 final String curInteractorStr = Settings.Secure.getStringForUser(
2610                         mContext.getContentResolver(),
2611                         Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
2612                 final ComponentName curInteractor = getCurInteractor(mCurUser);
2613                 // If there's no interactor and the user hasn't explicitly unset it, check if the
2614                 // modified package offers one.
2615                 if (curInteractor == null && !"".equals(curInteractorStr)) {
2616                     final VoiceInteractionServiceInfo availInteractorInfo
2617                             = findAvailInteractor(mCurUser, pkgName);
2618                     if (availInteractorInfo != null) {
2619                         final ComponentName availInteractor = new ComponentName(
2620                                 availInteractorInfo.getServiceInfo().packageName,
2621                                 availInteractorInfo.getServiceInfo().name);
2622                         setCurInteractor(availInteractor, mCurUser);
2623                     }
2624                 } else {
2625                     if (didSomePackagesChange()) {
2626                         // Package is changed
2627                         if (curInteractor != null && pkgName.equals(
2628                                 curInteractor.getPackageName())) {
2629                             switchImplementationIfNeeded(true);
2630                         }
2631                     } else {
2632                         // Only some components are changed
2633                         if (curInteractor != null
2634                                 && isComponentModified(curInteractor.getClassName())) {
2635                             switchImplementationIfNeeded(true);
2636                         }
2637                     }
2638                 }
2639             }
2640 
2641             @Override
2642             public void onSomePackagesChanged() {
2643                 int userHandle = getChangingUserId();
2644                 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle);
2645 
2646                 synchronized (VoiceInteractionManagerServiceStub.this) {
2647                     ComponentName curInteractor = getCurInteractor(userHandle);
2648                     ComponentName curRecognizer = getCurRecognizer(userHandle);
2649                     ComponentName curAssistant = getCurAssistant(userHandle);
2650                     if (curRecognizer == null) {
2651                         // Could a new recognizer appear when we don't have one pre-installed?
2652                         if (anyPackagesAppearing()) {
2653                             initRecognizer(userHandle);
2654                         }
2655                     }
2656 
2657                     if (curInteractor != null) {
2658                         int change = isPackageDisappearing(curInteractor.getPackageName());
2659                         if (change == PACKAGE_PERMANENT_CHANGE) {
2660                             // The currently set interactor is permanently gone; fall back to
2661                             // the default config.
2662                             setCurInteractor(null, userHandle);
2663                             setCurRecognizer(null, userHandle);
2664                             resetCurAssistant(userHandle);
2665                             initForUser(userHandle);
2666                             return;
2667                         }
2668 
2669                         change = isPackageAppearing(curInteractor.getPackageName());
2670                         if (change != PACKAGE_UNCHANGED) {
2671                             resetServicesIfNoRecognitionService(curInteractor, userHandle);
2672                             // If current interactor is now appearing, for any reason, then
2673                             // restart our connection with it.
2674                             if (mImpl != null && curInteractor.getPackageName().equals(
2675                                     mImpl.mComponent.getPackageName())) {
2676                                 switchImplementationIfNeededLocked(true);
2677                             }
2678                         }
2679                         return;
2680                     }
2681 
2682                     if (curAssistant != null) {
2683                         int change = isPackageDisappearing(curAssistant.getPackageName());
2684                         if (change == PACKAGE_PERMANENT_CHANGE) {
2685                             // If the currently set assistant is being removed, then we should
2686                             // reset back to the default state (which is probably that we prefer
2687                             // to have the default full voice interactor enabled).
2688                             setCurInteractor(null, userHandle);
2689                             setCurRecognizer(null, userHandle);
2690                             resetCurAssistant(userHandle);
2691                             initForUser(userHandle);
2692                             return;
2693                         }
2694                         change = isPackageAppearing(curAssistant.getPackageName());
2695                         if (change != PACKAGE_UNCHANGED) {
2696                             // It is possible to update Assistant without a voice interactor to one
2697                             // with a voice-interactor. We should make sure the recognition service
2698                             // is set to avoid boot loop.
2699                             resetServicesIfNoRecognitionService(curAssistant, userHandle);
2700                         }
2701                     }
2702 
2703                     if (curRecognizer != null) {
2704                         int change = isPackageDisappearing(curRecognizer.getPackageName());
2705                         if (change == PACKAGE_PERMANENT_CHANGE
2706                                 || change == PACKAGE_TEMPORARY_CHANGE) {
2707                             setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
2708 
2709                         } else if (isPackageModified(curRecognizer.getPackageName())) {
2710                             setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(),
2711                                     userHandle), userHandle);
2712                         }
2713                     }
2714                 }
2715             }
2716         };
2717 
getContextualSearchIntent(Bundle args)2718         private Intent getContextualSearchIntent(Bundle args) {
2719             String csPkgName = mContext.getResources()
2720                     .getString(R.string.config_defaultContextualSearchPackageName);
2721             if (csPkgName.isEmpty()) {
2722                 // Return null if csPackageName is not specified.
2723                 return null;
2724             }
2725             Intent launchIntent = new Intent(CS_INTENT_FILTER);
2726             launchIntent.setPackage(csPkgName);
2727             ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
2728                     launchIntent, PackageManager.MATCH_FACTORY_ONLY);
2729             if (resolveInfo == null) {
2730                 return null;
2731             }
2732             launchIntent.setComponent(resolveInfo.getComponentInfo().getComponentName());
2733             launchIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION
2734                     | FLAG_ACTIVITY_NO_USER_ACTION | FLAG_ACTIVITY_CLEAR_TASK);
2735             launchIntent.putExtras(args);
2736             boolean isAssistDataAllowed = mAtmInternal.isAssistDataAllowed();
2737             final List<ActivityAssistInfo> records = mAtmInternal.getTopVisibleActivities();
2738             ArrayList<String> visiblePackageNames = new ArrayList<>();
2739             boolean isManagedProfileVisible = false;
2740             for (ActivityAssistInfo record: records) {
2741                 // Add the package name to the list only if assist data is allowed.
2742                 if (isAssistDataAllowed) {
2743                     visiblePackageNames.add(record.getComponentName().getPackageName());
2744                 }
2745                 if (mDpmInternal != null
2746                         && mDpmInternal.isUserOrganizationManaged(record.getUserId())) {
2747                     isManagedProfileVisible = true;
2748                 }
2749             }
2750             final ScreenCapture.ScreenshotHardwareBuffer shb = mWmInternal.takeAssistScreenshot();
2751             final Bitmap bm = shb != null ? shb.asBitmap() : null;
2752             // Now that everything is fetched, putting it in the launchIntent.
2753             if (bm != null) {
2754                 launchIntent.putExtra(CS_KEY_FLAG_SECURE_FOUND, shb.containsSecureLayers());
2755                 // Only put the screenshot if assist data is allowed
2756                 if (isAssistDataAllowed) {
2757                     launchIntent.putExtra(CS_KEY_FLAG_SCREENSHOT, bm.asShared());
2758                 }
2759             }
2760             launchIntent.putExtra(CS_KEY_FLAG_IS_MANAGED_PROFILE_VISIBLE, isManagedProfileVisible);
2761             // Only put the list of visible package names if assist data is allowed
2762             if (isAssistDataAllowed) {
2763                 launchIntent.putExtra(CS_KEY_FLAG_VISIBLE_PACKAGE_NAMES, visiblePackageNames);
2764             }
2765 
2766             return launchIntent;
2767         }
2768 
2769         @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS)
startContextualSearch(Intent launchIntent, final int userId)2770         private boolean startContextualSearch(Intent launchIntent, final int userId) {
2771             // Contextual search starts with a frozen screen - so we launch without
2772             // any system animations or starting window.
2773             final ActivityOptions opts = ActivityOptions.makeCustomTaskAnimation(mContext,
2774                     /* enterResId= */ 0, /* exitResId= */ 0, null, null, null);
2775             opts.setDisableStartingWindow(true);
2776             int resultCode = mAtmInternal.startActivityWithScreenshot(launchIntent,
2777                     mContext.getPackageName(), Binder.getCallingUid(), Binder.getCallingPid(), null,
2778                     opts.toBundle(), userId);
2779             return resultCode == ActivityManager.START_SUCCESS;
2780         }
2781 
2782     }
2783 
2784     /**
2785      * End the latency tracking log for keyphrase hotword invocation.
2786      * The measurement covers from when the SoundTrigger HAL emits an event, captured in
2787      * {@link com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging}
2788      * to when the {@link android.service.voice.VoiceInteractionSession} system UI view is shown.
2789      */
2790     private final IVoiceInteractionSessionListener mLatencyLoggingListener =
2791             new IVoiceInteractionSessionListener.Stub() {
2792                 @Override
2793                 public void onVoiceSessionShown() throws RemoteException {}
2794 
2795                 @Override
2796                 public void onVoiceSessionHidden() throws RemoteException {}
2797 
2798                 @Override
2799                 public void onVoiceSessionWindowVisibilityChanged(boolean visible)
2800                         throws RemoteException {
2801                     if (visible) {
2802                         // The AlwaysOnHotwordDetector trigger latency is always completed here even
2803                         // if the reason the window was shown was not due to a SoundTrigger HAL
2804                         // event. It is expected that the latency will be canceled if shown for
2805                         // other invocation reasons, and this call becomes a noop.
2806                         HotwordMetricsLogger.stopHotwordTriggerToUiLatencySession(mContext);
2807                     }
2808                 }
2809 
2810                 @Override
2811                 public void onSetUiHints(Bundle args) throws RemoteException {}
2812 
2813                 @Override
2814                 public IBinder asBinder() {
2815                     return mServiceStub;
2816                 }
2817             };
2818 }
2819