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