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