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