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 17package com.android.server.voiceinteraction; 18 19import android.Manifest; 20import android.app.ActivityManager; 21import android.app.ActivityManagerInternal; 22import android.app.AppGlobals; 23import android.content.ComponentName; 24import android.content.ContentResolver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.pm.ApplicationInfo; 28import android.content.pm.IPackageManager; 29import android.content.pm.PackageManager; 30import android.content.pm.PackageManagerInternal; 31import android.content.pm.ResolveInfo; 32import android.content.pm.ServiceInfo; 33import android.content.res.Resources; 34import android.database.ContentObserver; 35import android.hardware.soundtrigger.IRecognitionStatusCallback; 36import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; 37import android.hardware.soundtrigger.SoundTrigger.ModuleProperties; 38import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; 39import android.os.Binder; 40import android.os.Bundle; 41import android.os.Handler; 42import android.os.IBinder; 43import android.os.Parcel; 44import android.os.RemoteCallbackList; 45import android.os.RemoteException; 46import android.os.UserHandle; 47import android.provider.Settings; 48import android.service.voice.IVoiceInteractionService; 49import android.service.voice.IVoiceInteractionSession; 50import android.service.voice.VoiceInteractionManagerInternal; 51import android.service.voice.VoiceInteractionService; 52import android.service.voice.VoiceInteractionServiceInfo; 53import android.service.voice.VoiceInteractionSession; 54import android.speech.RecognitionService; 55import android.text.TextUtils; 56import android.util.Log; 57import android.util.Slog; 58 59import com.android.internal.app.IVoiceInteractionSessionListener; 60import com.android.internal.app.IVoiceInteractionManagerService; 61import com.android.internal.app.IVoiceInteractionSessionShowCallback; 62import com.android.internal.app.IVoiceInteractor; 63import com.android.internal.content.PackageMonitor; 64import com.android.internal.os.BackgroundThread; 65import com.android.server.LocalServices; 66import com.android.server.SystemService; 67import com.android.server.UiThread; 68import com.android.server.soundtrigger.SoundTriggerInternal; 69 70import java.io.FileDescriptor; 71import java.io.PrintWriter; 72import java.util.List; 73import java.util.TreeSet; 74 75/** 76 * SystemService that publishes an IVoiceInteractionManagerService. 77 */ 78public class VoiceInteractionManagerService extends SystemService { 79 static final String TAG = "VoiceInteractionManagerService"; 80 static final boolean DEBUG = false; 81 82 final Context mContext; 83 final ContentResolver mResolver; 84 final DatabaseHelper mDbHelper; 85 final ActivityManagerInternal mAmInternal; 86 final TreeSet<Integer> mLoadedKeyphraseIds; 87 SoundTriggerInternal mSoundTriggerInternal; 88 89 private final RemoteCallbackList<IVoiceInteractionSessionListener> 90 mVoiceInteractionSessionListeners = new RemoteCallbackList<>(); 91 92 public VoiceInteractionManagerService(Context context) { 93 super(context); 94 mContext = context; 95 mResolver = context.getContentResolver(); 96 mDbHelper = new DatabaseHelper(context); 97 mServiceStub = new VoiceInteractionManagerServiceStub(); 98 mAmInternal = LocalServices.getService(ActivityManagerInternal.class); 99 mLoadedKeyphraseIds = new TreeSet<Integer>(); 100 101 PackageManagerInternal packageManagerInternal = LocalServices.getService( 102 PackageManagerInternal.class); 103 packageManagerInternal.setVoiceInteractionPackagesProvider( 104 new PackageManagerInternal.PackagesProvider() { 105 @Override 106 public String[] getPackages(int userId) { 107 mServiceStub.initForUser(userId); 108 ComponentName interactor = mServiceStub.getCurInteractor(userId); 109 if (interactor != null) { 110 return new String[] {interactor.getPackageName()}; 111 } 112 return null; 113 } 114 }); 115 } 116 117 @Override 118 public void onStart() { 119 publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub); 120 publishLocalService(VoiceInteractionManagerInternal.class, new LocalService()); 121 } 122 123 @Override 124 public void onBootPhase(int phase) { 125 if (PHASE_SYSTEM_SERVICES_READY == phase) { 126 mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class); 127 } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { 128 mServiceStub.systemRunning(isSafeMode()); 129 } 130 } 131 132 @Override 133 public void onStartUser(int userHandle) { 134 mServiceStub.initForUser(userHandle); 135 } 136 137 @Override 138 public void onUnlockUser(int userHandle) { 139 mServiceStub.initForUser(userHandle); 140 mServiceStub.switchImplementationIfNeeded(false); 141 } 142 143 @Override 144 public void onSwitchUser(int userHandle) { 145 mServiceStub.switchUser(userHandle); 146 } 147 148 class LocalService extends VoiceInteractionManagerInternal { 149 @Override 150 public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) { 151 if (DEBUG) { 152 Slog.i(TAG, "startLocalVoiceInteraction " + callingActivity); 153 } 154 VoiceInteractionManagerService.this.mServiceStub.startLocalVoiceInteraction( 155 callingActivity, options); 156 } 157 158 @Override 159 public boolean supportsLocalVoiceInteraction() { 160 return VoiceInteractionManagerService.this.mServiceStub.supportsLocalVoiceInteraction(); 161 } 162 163 @Override 164 public void stopLocalVoiceInteraction(IBinder callingActivity) { 165 if (DEBUG) { 166 Slog.i(TAG, "stopLocalVoiceInteraction " + callingActivity); 167 } 168 VoiceInteractionManagerService.this.mServiceStub.stopLocalVoiceInteraction( 169 callingActivity); 170 } 171 } 172 173 // implementation entry point and binder service 174 private final VoiceInteractionManagerServiceStub mServiceStub; 175 176 class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub { 177 178 VoiceInteractionManagerServiceImpl mImpl; 179 180 private boolean mSafeMode; 181 private int mCurUser; 182 private final boolean mEnableService; 183 184 VoiceInteractionManagerServiceStub() { 185 mEnableService = shouldEnableService(mContext.getResources()); 186 } 187 188 // TODO: VI Make sure the caller is the current user or profile 189 void startLocalVoiceInteraction(final IBinder token, Bundle options) { 190 if (mImpl == null) return; 191 192 final long caller = Binder.clearCallingIdentity(); 193 try { 194 mImpl.showSessionLocked(options, 195 VoiceInteractionSession.SHOW_SOURCE_ACTIVITY, 196 new IVoiceInteractionSessionShowCallback.Stub() { 197 @Override 198 public void onFailed() { 199 } 200 201 @Override 202 public void onShown() { 203 mAmInternal.onLocalVoiceInteractionStarted(token, 204 mImpl.mActiveSession.mSession, 205 mImpl.mActiveSession.mInteractor); 206 } 207 }, 208 token); 209 } finally { 210 Binder.restoreCallingIdentity(caller); 211 } 212 } 213 214 public void stopLocalVoiceInteraction(IBinder callingActivity) { 215 if (mImpl == null) return; 216 217 final long caller = Binder.clearCallingIdentity(); 218 try { 219 mImpl.finishLocked(callingActivity, true); 220 } finally { 221 Binder.restoreCallingIdentity(caller); 222 } 223 } 224 225 public boolean supportsLocalVoiceInteraction() { 226 if (mImpl == null) return false; 227 228 return mImpl.supportsLocalVoiceInteraction(); 229 } 230 231 @Override 232 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 233 throws RemoteException { 234 try { 235 return super.onTransact(code, data, reply, flags); 236 } catch (RuntimeException e) { 237 // The activity manager only throws security exceptions, so let's 238 // log all others. 239 if (!(e instanceof SecurityException)) { 240 Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e); 241 } 242 throw e; 243 } 244 } 245 246 public void initForUser(int userHandle) { 247 if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle); 248 String curInteractorStr = Settings.Secure.getStringForUser( 249 mContext.getContentResolver(), 250 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle); 251 ComponentName curRecognizer = getCurRecognizer(userHandle); 252 VoiceInteractionServiceInfo curInteractorInfo = null; 253 if (DEBUG) Slog.d(TAG, "curInteractorStr=" + curInteractorStr 254 + " curRecognizer=" + curRecognizer); 255 if (curInteractorStr == null && curRecognizer != null && mEnableService) { 256 // If there is no interactor setting, that means we are upgrading 257 // from an older platform version. If the current recognizer is not 258 // set or matches the preferred recognizer, then we want to upgrade 259 // the user to have the default voice interaction service enabled. 260 // Note that we don't do this for low-RAM devices, since we aren't 261 // supporting voice interaction services there. 262 curInteractorInfo = findAvailInteractor(userHandle, curRecognizer.getPackageName()); 263 if (curInteractorInfo != null) { 264 // Looks good! We'll apply this one. To make it happen, we clear the 265 // recognizer so that we don't think we have anything set and will 266 // re-apply the settings. 267 if (DEBUG) Slog.d(TAG, "No set interactor, found avail: " 268 + curInteractorInfo.getServiceInfo().name); 269 curRecognizer = null; 270 } 271 } 272 273 // If forceInteractorPackage exists, try to apply the interactor from this package if 274 // possible and ignore the regular interactor setting. 275 String forceInteractorPackage = 276 getForceVoiceInteractionServicePackage(mContext.getResources()); 277 if (forceInteractorPackage != null) { 278 curInteractorInfo = findAvailInteractor(userHandle, forceInteractorPackage); 279 if (curInteractorInfo != null) { 280 // We'll apply this one. Clear the recognizer and re-apply the settings. 281 curRecognizer = null; 282 } 283 } 284 285 // If we are on a svelte device, make sure an interactor is not currently 286 // enabled; if it is, turn it off. 287 if (!mEnableService && curInteractorStr != null) { 288 if (!TextUtils.isEmpty(curInteractorStr)) { 289 if (DEBUG) Slog.d(TAG, "Svelte device; disabling interactor"); 290 setCurInteractor(null, userHandle); 291 curInteractorStr = ""; 292 } 293 } 294 295 if (curRecognizer != null) { 296 // If we already have at least a recognizer, then we probably want to 297 // leave things as they are... unless something has disappeared. 298 IPackageManager pm = AppGlobals.getPackageManager(); 299 ServiceInfo interactorInfo = null; 300 ServiceInfo recognizerInfo = null; 301 ComponentName curInteractor = !TextUtils.isEmpty(curInteractorStr) 302 ? ComponentName.unflattenFromString(curInteractorStr) : null; 303 try { 304 recognizerInfo = pm.getServiceInfo(curRecognizer, 0, userHandle); 305 if (curInteractor != null) { 306 interactorInfo = pm.getServiceInfo(curInteractor, 0, userHandle); 307 } 308 } catch (RemoteException e) { 309 } 310 // If the apps for the currently set components still exist, then all is okay. 311 if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) { 312 if (DEBUG) Slog.d(TAG, "Current interactor/recognizer okay, done!"); 313 return; 314 } 315 if (DEBUG) Slog.d(TAG, "Bad recognizer (" + recognizerInfo + ") or interactor (" 316 + interactorInfo + ")"); 317 } 318 319 // Initializing settings, look for an interactor first (but only on non-svelte). 320 if (curInteractorInfo == null && mEnableService) { 321 curInteractorInfo = findAvailInteractor(userHandle, null); 322 } 323 324 if (curInteractorInfo != null) { 325 // Eventually it will be an error to not specify this. 326 setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName, 327 curInteractorInfo.getServiceInfo().name), userHandle); 328 if (curInteractorInfo.getRecognitionService() != null) { 329 setCurRecognizer( 330 new ComponentName(curInteractorInfo.getServiceInfo().packageName, 331 curInteractorInfo.getRecognitionService()), userHandle); 332 return; 333 } 334 } 335 336 // No voice interactor, we'll just set up a simple recognizer. 337 curRecognizer = findAvailRecognizer(null, userHandle); 338 if (curRecognizer != null) { 339 if (curInteractorInfo == null) { 340 setCurInteractor(null, userHandle); 341 } 342 setCurRecognizer(curRecognizer, userHandle); 343 } 344 } 345 346 private boolean shouldEnableService(Resources res) { 347 // VoiceInteractionService should not be enabled on low ram devices unless it has the config flag. 348 return !ActivityManager.isLowRamDeviceStatic() || 349 getForceVoiceInteractionServicePackage(res) != null; 350 } 351 352 private String getForceVoiceInteractionServicePackage(Resources res) { 353 String interactorPackage = 354 res.getString(com.android.internal.R.string.config_forceVoiceInteractionServicePackage); 355 return TextUtils.isEmpty(interactorPackage) ? null : interactorPackage; 356 } 357 358 public void systemRunning(boolean safeMode) { 359 mSafeMode = safeMode; 360 361 mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(), 362 UserHandle.ALL, true); 363 new SettingsObserver(UiThread.getHandler()); 364 365 synchronized (this) { 366 mCurUser = ActivityManager.getCurrentUser(); 367 switchImplementationIfNeededLocked(false); 368 } 369 } 370 371 public void switchUser(int userHandle) { 372 synchronized (this) { 373 mCurUser = userHandle; 374 switchImplementationIfNeededLocked(false); 375 } 376 } 377 378 void switchImplementationIfNeeded(boolean force) { 379 synchronized (this) { 380 switchImplementationIfNeededLocked(force); 381 } 382 } 383 384 void switchImplementationIfNeededLocked(boolean force) { 385 if (!mSafeMode) { 386 String curService = Settings.Secure.getStringForUser( 387 mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser); 388 ComponentName serviceComponent = null; 389 ServiceInfo serviceInfo = null; 390 if (curService != null && !curService.isEmpty()) { 391 try { 392 serviceComponent = ComponentName.unflattenFromString(curService); 393 serviceInfo = AppGlobals.getPackageManager() 394 .getServiceInfo(serviceComponent, 0, mCurUser); 395 } catch (RuntimeException | RemoteException e) { 396 Slog.wtf(TAG, "Bad voice interaction service name " + curService, e); 397 serviceComponent = null; 398 serviceInfo = null; 399 } 400 } 401 402 if (force || mImpl == null || mImpl.mUser != mCurUser 403 || !mImpl.mComponent.equals(serviceComponent)) { 404 unloadAllKeyphraseModels(); 405 if (mImpl != null) { 406 mImpl.shutdownLocked(); 407 } 408 if (serviceComponent != null && serviceInfo != null) { 409 mImpl = new VoiceInteractionManagerServiceImpl(mContext, 410 UiThread.getHandler(), this, mCurUser, serviceComponent); 411 mImpl.startLocked(); 412 } else { 413 mImpl = null; 414 } 415 } 416 } 417 } 418 419 VoiceInteractionServiceInfo findAvailInteractor(int userHandle, String packageName) { 420 List<ResolveInfo> available = 421 mContext.getPackageManager().queryIntentServicesAsUser( 422 new Intent(VoiceInteractionService.SERVICE_INTERFACE), 423 PackageManager.MATCH_DIRECT_BOOT_AWARE 424 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE 425 | PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userHandle); 426 int numAvailable = available.size(); 427 428 if (numAvailable == 0) { 429 Slog.w(TAG, "no available voice interaction services found for user " + userHandle); 430 return null; 431 } else { 432 // Find first system package. We never want to allow third party services to 433 // be automatically selected, because those require approval of the user. 434 VoiceInteractionServiceInfo foundInfo = null; 435 for (int i=0; i<numAvailable; i++) { 436 ServiceInfo cur = available.get(i).serviceInfo; 437 if ((cur.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { 438 ComponentName comp = new ComponentName(cur.packageName, cur.name); 439 try { 440 VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo( 441 mContext.getPackageManager(), comp, userHandle); 442 if (info.getParseError() == null) { 443 if (packageName == null || info.getServiceInfo().packageName.equals( 444 packageName)) { 445 if (foundInfo == null) { 446 foundInfo = info; 447 } else { 448 Slog.w(TAG, "More than one voice interaction service, " 449 + "picking first " 450 + new ComponentName( 451 foundInfo.getServiceInfo().packageName, 452 foundInfo.getServiceInfo().name) 453 + " over " 454 + new ComponentName(cur.packageName, cur.name)); 455 } 456 } 457 } else { 458 Slog.w(TAG, "Bad interaction service " + comp + ": " 459 + info.getParseError()); 460 } 461 } catch (PackageManager.NameNotFoundException e) { 462 Slog.w(TAG, "Failure looking up interaction service " + comp); 463 } 464 } 465 } 466 467 return foundInfo; 468 } 469 } 470 471 ComponentName getCurInteractor(int userHandle) { 472 String curInteractor = Settings.Secure.getStringForUser( 473 mContext.getContentResolver(), 474 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle); 475 if (TextUtils.isEmpty(curInteractor)) { 476 return null; 477 } 478 if (DEBUG) Slog.d(TAG, "getCurInteractor curInteractor=" + curInteractor 479 + " user=" + userHandle); 480 return ComponentName.unflattenFromString(curInteractor); 481 } 482 483 void setCurInteractor(ComponentName comp, int userHandle) { 484 Settings.Secure.putStringForUser(mContext.getContentResolver(), 485 Settings.Secure.VOICE_INTERACTION_SERVICE, 486 comp != null ? comp.flattenToShortString() : "", userHandle); 487 if (DEBUG) Slog.d(TAG, "setCurInteractor comp=" + comp 488 + " user=" + userHandle); 489 } 490 491 ComponentName findAvailRecognizer(String prefPackage, int userHandle) { 492 List<ResolveInfo> available = 493 mContext.getPackageManager().queryIntentServicesAsUser( 494 new Intent(RecognitionService.SERVICE_INTERFACE), 0, userHandle); 495 int numAvailable = available.size(); 496 497 if (numAvailable == 0) { 498 Slog.w(TAG, "no available voice recognition services found for user " + userHandle); 499 return null; 500 } else { 501 if (prefPackage != null) { 502 for (int i=0; i<numAvailable; i++) { 503 ServiceInfo serviceInfo = available.get(i).serviceInfo; 504 if (prefPackage.equals(serviceInfo.packageName)) { 505 return new ComponentName(serviceInfo.packageName, serviceInfo.name); 506 } 507 } 508 } 509 if (numAvailable > 1) { 510 Slog.w(TAG, "more than one voice recognition service found, picking first"); 511 } 512 513 ServiceInfo serviceInfo = available.get(0).serviceInfo; 514 return new ComponentName(serviceInfo.packageName, serviceInfo.name); 515 } 516 } 517 518 ComponentName getCurRecognizer(int userHandle) { 519 String curRecognizer = Settings.Secure.getStringForUser( 520 mContext.getContentResolver(), 521 Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle); 522 if (TextUtils.isEmpty(curRecognizer)) { 523 return null; 524 } 525 if (DEBUG) Slog.d(TAG, "getCurRecognizer curRecognizer=" + curRecognizer 526 + " user=" + userHandle); 527 return ComponentName.unflattenFromString(curRecognizer); 528 } 529 530 void setCurRecognizer(ComponentName comp, int userHandle) { 531 Settings.Secure.putStringForUser(mContext.getContentResolver(), 532 Settings.Secure.VOICE_RECOGNITION_SERVICE, 533 comp != null ? comp.flattenToShortString() : "", userHandle); 534 if (DEBUG) Slog.d(TAG, "setCurRecognizer comp=" + comp 535 + " user=" + userHandle); 536 } 537 538 ComponentName getCurAssistant(int userHandle) { 539 String curAssistant = Settings.Secure.getStringForUser( 540 mContext.getContentResolver(), 541 Settings.Secure.ASSISTANT, userHandle); 542 if (TextUtils.isEmpty(curAssistant)) { 543 return null; 544 } 545 if (DEBUG) Slog.d(TAG, "getCurAssistant curAssistant=" + curAssistant 546 + " user=" + userHandle); 547 return ComponentName.unflattenFromString(curAssistant); 548 } 549 550 void resetCurAssistant(int userHandle) { 551 Settings.Secure.putStringForUser(mContext.getContentResolver(), 552 Settings.Secure.ASSISTANT, null, userHandle); 553 } 554 555 @Override 556 public void showSession(IVoiceInteractionService service, Bundle args, int flags) { 557 synchronized (this) { 558 if (mImpl == null || mImpl.mService == null 559 || service.asBinder() != mImpl.mService.asBinder()) { 560 throw new SecurityException( 561 "Caller is not the current voice interaction service"); 562 } 563 final long caller = Binder.clearCallingIdentity(); 564 try { 565 mImpl.showSessionLocked(args, flags, null, null); 566 } finally { 567 Binder.restoreCallingIdentity(caller); 568 } 569 } 570 } 571 572 @Override 573 public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session, 574 IVoiceInteractor interactor) { 575 synchronized (this) { 576 if (mImpl == null) { 577 throw new SecurityException( 578 "deliverNewSession without running voice interaction service"); 579 } 580 final long caller = Binder.clearCallingIdentity(); 581 try { 582 return mImpl.deliverNewSessionLocked(token, session, interactor); 583 } finally { 584 Binder.restoreCallingIdentity(caller); 585 } 586 } 587 } 588 589 @Override 590 public boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) { 591 synchronized (this) { 592 if (mImpl == null) { 593 Slog.w(TAG, "showSessionFromSession without running voice interaction service"); 594 return false; 595 } 596 final long caller = Binder.clearCallingIdentity(); 597 try { 598 return mImpl.showSessionLocked(sessionArgs, flags, null, null); 599 } finally { 600 Binder.restoreCallingIdentity(caller); 601 } 602 } 603 } 604 605 @Override 606 public boolean hideSessionFromSession(IBinder token) { 607 synchronized (this) { 608 if (mImpl == null) { 609 Slog.w(TAG, "hideSessionFromSession without running voice interaction service"); 610 return false; 611 } 612 final long caller = Binder.clearCallingIdentity(); 613 try { 614 return mImpl.hideSessionLocked(); 615 } finally { 616 Binder.restoreCallingIdentity(caller); 617 } 618 } 619 } 620 621 @Override 622 public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) { 623 synchronized (this) { 624 if (mImpl == null) { 625 Slog.w(TAG, "startVoiceActivity without running voice interaction service"); 626 return ActivityManager.START_CANCELED; 627 } 628 final int callingPid = Binder.getCallingPid(); 629 final int callingUid = Binder.getCallingUid(); 630 final long caller = Binder.clearCallingIdentity(); 631 try { 632 return mImpl.startVoiceActivityLocked(callingPid, callingUid, token, 633 intent, resolvedType); 634 } finally { 635 Binder.restoreCallingIdentity(caller); 636 } 637 } 638 } 639 640 @Override 641 public void setKeepAwake(IBinder token, boolean keepAwake) { 642 synchronized (this) { 643 if (mImpl == null) { 644 Slog.w(TAG, "setKeepAwake without running voice interaction service"); 645 return; 646 } 647 final long caller = Binder.clearCallingIdentity(); 648 try { 649 mImpl.setKeepAwakeLocked(token, keepAwake); 650 } finally { 651 Binder.restoreCallingIdentity(caller); 652 } 653 } 654 } 655 656 @Override 657 public void closeSystemDialogs(IBinder token) { 658 synchronized (this) { 659 if (mImpl == null) { 660 Slog.w(TAG, "closeSystemDialogs without running voice interaction service"); 661 return; 662 } 663 final long caller = Binder.clearCallingIdentity(); 664 try { 665 mImpl.closeSystemDialogsLocked(token); 666 } finally { 667 Binder.restoreCallingIdentity(caller); 668 } 669 } 670 } 671 672 @Override 673 public void finish(IBinder token) { 674 synchronized (this) { 675 if (mImpl == null) { 676 Slog.w(TAG, "finish without running voice interaction service"); 677 return; 678 } 679 final long caller = Binder.clearCallingIdentity(); 680 try { 681 mImpl.finishLocked(token, false); 682 } finally { 683 Binder.restoreCallingIdentity(caller); 684 } 685 } 686 } 687 688 @Override 689 public void setDisabledShowContext(int flags) { 690 synchronized (this) { 691 if (mImpl == null) { 692 Slog.w(TAG, "setDisabledShowContext without running voice interaction service"); 693 return; 694 } 695 final int callingUid = Binder.getCallingUid(); 696 final long caller = Binder.clearCallingIdentity(); 697 try { 698 mImpl.setDisabledShowContextLocked(callingUid, flags); 699 } finally { 700 Binder.restoreCallingIdentity(caller); 701 } 702 } 703 } 704 705 @Override 706 public int getDisabledShowContext() { 707 synchronized (this) { 708 if (mImpl == null) { 709 Slog.w(TAG, "getDisabledShowContext without running voice interaction service"); 710 return 0; 711 } 712 final int callingUid = Binder.getCallingUid(); 713 final long caller = Binder.clearCallingIdentity(); 714 try { 715 return mImpl.getDisabledShowContextLocked(callingUid); 716 } finally { 717 Binder.restoreCallingIdentity(caller); 718 } 719 } 720 } 721 722 @Override 723 public int getUserDisabledShowContext() { 724 synchronized (this) { 725 if (mImpl == null) { 726 Slog.w(TAG, 727 "getUserDisabledShowContext without running voice interaction service"); 728 return 0; 729 } 730 final int callingUid = Binder.getCallingUid(); 731 final long caller = Binder.clearCallingIdentity(); 732 try { 733 return mImpl.getUserDisabledShowContextLocked(callingUid); 734 } finally { 735 Binder.restoreCallingIdentity(caller); 736 } 737 } 738 } 739 740 //----------------- Model management APIs --------------------------------// 741 742 @Override 743 public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 744 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); 745 746 if (bcp47Locale == null) { 747 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel"); 748 } 749 750 final int callingUid = UserHandle.getCallingUserId(); 751 final long caller = Binder.clearCallingIdentity(); 752 try { 753 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 754 } finally { 755 Binder.restoreCallingIdentity(caller); 756 } 757 } 758 759 @Override 760 public int updateKeyphraseSoundModel(KeyphraseSoundModel model) { 761 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); 762 if (model == null) { 763 throw new IllegalArgumentException("Model must not be null"); 764 } 765 766 final long caller = Binder.clearCallingIdentity(); 767 try { 768 if (mDbHelper.updateKeyphraseSoundModel(model)) { 769 synchronized (this) { 770 // Notify the voice interaction service of a change in sound models. 771 if (mImpl != null && mImpl.mService != null) { 772 mImpl.notifySoundModelsChangedLocked(); 773 } 774 } 775 return SoundTriggerInternal.STATUS_OK; 776 } else { 777 return SoundTriggerInternal.STATUS_ERROR; 778 } 779 } finally { 780 Binder.restoreCallingIdentity(caller); 781 } 782 } 783 784 @Override 785 public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 786 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); 787 788 if (bcp47Locale == null) { 789 throw new IllegalArgumentException( 790 "Illegal argument(s) in deleteKeyphraseSoundModel"); 791 } 792 793 final int callingUid = UserHandle.getCallingUserId(); 794 final long caller = Binder.clearCallingIdentity(); 795 boolean deleted = false; 796 try { 797 int unloadStatus = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId); 798 if (unloadStatus != SoundTriggerInternal.STATUS_OK) { 799 Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus); 800 } 801 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 802 return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR; 803 } finally { 804 if (deleted) { 805 synchronized (this) { 806 // Notify the voice interaction service of a change in sound models. 807 if (mImpl != null && mImpl.mService != null) { 808 mImpl.notifySoundModelsChangedLocked(); 809 } 810 mLoadedKeyphraseIds.remove(keyphraseId); 811 } 812 } 813 Binder.restoreCallingIdentity(caller); 814 } 815 } 816 817 //----------------- SoundTrigger APIs --------------------------------// 818 @Override 819 public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId, 820 String bcp47Locale) { 821 synchronized (this) { 822 if (mImpl == null || mImpl.mService == null 823 || service.asBinder() != mImpl.mService.asBinder()) { 824 throw new SecurityException( 825 "Caller is not the current voice interaction service"); 826 } 827 } 828 829 if (bcp47Locale == null) { 830 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase"); 831 } 832 833 final int callingUid = UserHandle.getCallingUserId(); 834 final long caller = Binder.clearCallingIdentity(); 835 try { 836 KeyphraseSoundModel model = 837 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 838 return model != null; 839 } finally { 840 Binder.restoreCallingIdentity(caller); 841 } 842 } 843 844 @Override 845 public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) { 846 // Allow the call if this is the current voice interaction service. 847 synchronized (this) { 848 if (mImpl == null || mImpl.mService == null 849 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 850 throw new SecurityException( 851 "Caller is not the current voice interaction service"); 852 } 853 854 final long caller = Binder.clearCallingIdentity(); 855 try { 856 return mSoundTriggerInternal.getModuleProperties(); 857 } finally { 858 Binder.restoreCallingIdentity(caller); 859 } 860 } 861 } 862 863 @Override 864 public int startRecognition(IVoiceInteractionService service, int keyphraseId, 865 String bcp47Locale, IRecognitionStatusCallback callback, 866 RecognitionConfig recognitionConfig) { 867 // Allow the call if this is the current voice interaction service. 868 synchronized (this) { 869 if (mImpl == null || mImpl.mService == null 870 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 871 throw new SecurityException( 872 "Caller is not the current voice interaction service"); 873 } 874 875 if (callback == null || recognitionConfig == null || bcp47Locale == null) { 876 throw new IllegalArgumentException("Illegal argument(s) in startRecognition"); 877 } 878 } 879 880 int callingUid = UserHandle.getCallingUserId(); 881 final long caller = Binder.clearCallingIdentity(); 882 try { 883 KeyphraseSoundModel soundModel = 884 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 885 if (soundModel == null 886 || soundModel.uuid == null 887 || soundModel.keyphrases == null) { 888 Slog.w(TAG, "No matching sound model found in startRecognition"); 889 return SoundTriggerInternal.STATUS_ERROR; 890 } else { 891 // Regardless of the status of the start recognition, we need to make sure 892 // that we unload this model if needed later. 893 synchronized (this) { 894 mLoadedKeyphraseIds.add(keyphraseId); 895 } 896 return mSoundTriggerInternal.startRecognition( 897 keyphraseId, soundModel, callback, recognitionConfig); 898 } 899 } finally { 900 Binder.restoreCallingIdentity(caller); 901 } 902 } 903 904 @Override 905 public int stopRecognition(IVoiceInteractionService service, int keyphraseId, 906 IRecognitionStatusCallback callback) { 907 // Allow the call if this is the current voice interaction service. 908 synchronized (this) { 909 if (mImpl == null || mImpl.mService == null 910 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 911 throw new SecurityException( 912 "Caller is not the current voice interaction service"); 913 } 914 } 915 916 final long caller = Binder.clearCallingIdentity(); 917 try { 918 return mSoundTriggerInternal.stopRecognition(keyphraseId, callback); 919 } finally { 920 Binder.restoreCallingIdentity(caller); 921 } 922 } 923 924 private synchronized void unloadAllKeyphraseModels() { 925 for (int keyphraseId : mLoadedKeyphraseIds) { 926 final long caller = Binder.clearCallingIdentity(); 927 try { 928 int status = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId); 929 if (status != SoundTriggerInternal.STATUS_OK) { 930 Slog.w(TAG, "Failed to unload keyphrase " + keyphraseId + ":" + status); 931 } 932 } finally { 933 Binder.restoreCallingIdentity(caller); 934 } 935 } 936 mLoadedKeyphraseIds.clear(); 937 } 938 939 @Override 940 public ComponentName getActiveServiceComponentName() { 941 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 942 synchronized (this) { 943 return mImpl != null ? mImpl.mComponent : null; 944 } 945 } 946 947 @Override 948 public boolean showSessionForActiveService(Bundle args, int sourceFlags, 949 IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) { 950 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 951 synchronized (this) { 952 if (mImpl == null) { 953 Slog.w(TAG, "showSessionForActiveService without running voice interaction" 954 + "service"); 955 return false; 956 } 957 final long caller = Binder.clearCallingIdentity(); 958 try { 959 return mImpl.showSessionLocked(args, 960 sourceFlags 961 | VoiceInteractionSession.SHOW_WITH_ASSIST 962 | VoiceInteractionSession.SHOW_WITH_SCREENSHOT, 963 showCallback, activityToken); 964 } finally { 965 Binder.restoreCallingIdentity(caller); 966 } 967 } 968 } 969 970 @Override 971 public void hideCurrentSession() throws RemoteException { 972 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 973 synchronized (this) { 974 if (mImpl == null) { 975 return; 976 } 977 final long caller = Binder.clearCallingIdentity(); 978 try { 979 if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) { 980 try { 981 mImpl.mActiveSession.mSession.closeSystemDialogs(); 982 } catch (RemoteException e) { 983 Log.w(TAG, "Failed to call closeSystemDialogs", e); 984 } 985 } 986 } finally { 987 Binder.restoreCallingIdentity(caller); 988 } 989 } 990 } 991 992 @Override 993 public void launchVoiceAssistFromKeyguard() { 994 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 995 synchronized (this) { 996 if (mImpl == null) { 997 Slog.w(TAG, "launchVoiceAssistFromKeyguard without running voice interaction" 998 + "service"); 999 return; 1000 } 1001 final long caller = Binder.clearCallingIdentity(); 1002 try { 1003 mImpl.launchVoiceAssistFromKeyguard(); 1004 } finally { 1005 Binder.restoreCallingIdentity(caller); 1006 } 1007 } 1008 } 1009 1010 @Override 1011 public boolean isSessionRunning() { 1012 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 1013 synchronized (this) { 1014 return mImpl != null && mImpl.mActiveSession != null; 1015 } 1016 } 1017 1018 @Override 1019 public boolean activeServiceSupportsAssist() { 1020 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 1021 synchronized (this) { 1022 return mImpl != null && mImpl.mInfo != null && mImpl.mInfo.getSupportsAssist(); 1023 } 1024 } 1025 1026 @Override 1027 public boolean activeServiceSupportsLaunchFromKeyguard() throws RemoteException { 1028 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 1029 synchronized (this) { 1030 return mImpl != null && mImpl.mInfo != null 1031 && mImpl.mInfo.getSupportsLaunchFromKeyguard(); 1032 } 1033 } 1034 1035 @Override 1036 public void onLockscreenShown() { 1037 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 1038 synchronized (this) { 1039 if (mImpl == null) { 1040 return; 1041 } 1042 final long caller = Binder.clearCallingIdentity(); 1043 try { 1044 if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) { 1045 try { 1046 mImpl.mActiveSession.mSession.onLockscreenShown(); 1047 } catch (RemoteException e) { 1048 Log.w(TAG, "Failed to call onLockscreenShown", e); 1049 } 1050 } 1051 } finally { 1052 Binder.restoreCallingIdentity(caller); 1053 } 1054 } 1055 } 1056 1057 @Override 1058 public void registerVoiceInteractionSessionListener( 1059 IVoiceInteractionSessionListener listener) { 1060 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 1061 synchronized (this) { 1062 mVoiceInteractionSessionListeners.register(listener); 1063 } 1064 } 1065 1066 public void onSessionShown() { 1067 synchronized (this) { 1068 final int size = mVoiceInteractionSessionListeners.beginBroadcast(); 1069 for (int i = 0; i < size; ++i) { 1070 final IVoiceInteractionSessionListener listener = 1071 mVoiceInteractionSessionListeners.getBroadcastItem(i); 1072 try { 1073 listener.onVoiceSessionShown(); 1074 } catch (RemoteException e) { 1075 Slog.e(TAG, "Error delivering voice interaction open event.", e); 1076 } 1077 } 1078 mVoiceInteractionSessionListeners.finishBroadcast(); 1079 } 1080 } 1081 1082 public void onSessionHidden() { 1083 synchronized (this) { 1084 final int size = mVoiceInteractionSessionListeners.beginBroadcast(); 1085 for (int i = 0; i < size; ++i) { 1086 final IVoiceInteractionSessionListener listener = 1087 mVoiceInteractionSessionListeners.getBroadcastItem(i); 1088 try { 1089 listener.onVoiceSessionHidden(); 1090 1091 } catch (RemoteException e) { 1092 Slog.e(TAG, "Error delivering voice interaction closed event.", e); 1093 } 1094 } 1095 mVoiceInteractionSessionListeners.finishBroadcast(); 1096 } 1097 } 1098 1099 @Override 1100 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1101 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 1102 != PackageManager.PERMISSION_GRANTED) { 1103 pw.println("Permission Denial: can't dump PowerManager from from pid=" 1104 + Binder.getCallingPid() 1105 + ", uid=" + Binder.getCallingUid()); 1106 return; 1107 } 1108 synchronized (this) { 1109 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)"); 1110 pw.println(" mEnableService: " + mEnableService); 1111 if (mImpl == null) { 1112 pw.println(" (No active implementation)"); 1113 return; 1114 } 1115 mImpl.dumpLocked(fd, pw, args); 1116 } 1117 mSoundTriggerInternal.dump(fd, pw, args); 1118 } 1119 1120 private void enforceCallingPermission(String permission) { 1121 if (mContext.checkCallingOrSelfPermission(permission) 1122 != PackageManager.PERMISSION_GRANTED) { 1123 throw new SecurityException("Caller does not hold the permission " + permission); 1124 } 1125 } 1126 1127 class SettingsObserver extends ContentObserver { 1128 SettingsObserver(Handler handler) { 1129 super(handler); 1130 ContentResolver resolver = mContext.getContentResolver(); 1131 resolver.registerContentObserver(Settings.Secure.getUriFor( 1132 Settings.Secure.VOICE_INTERACTION_SERVICE), false, this, 1133 UserHandle.USER_ALL); 1134 } 1135 1136 @Override public void onChange(boolean selfChange) { 1137 synchronized (VoiceInteractionManagerServiceStub.this) { 1138 switchImplementationIfNeededLocked(false); 1139 } 1140 } 1141 } 1142 1143 PackageMonitor mPackageMonitor = new PackageMonitor() { 1144 @Override 1145 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 1146 if (DEBUG) Slog.d(TAG, "onHandleForceStop uid=" + uid + " doit=" + doit); 1147 1148 int userHandle = UserHandle.getUserId(uid); 1149 ComponentName curInteractor = getCurInteractor(userHandle); 1150 ComponentName curRecognizer = getCurRecognizer(userHandle); 1151 boolean hit = false; 1152 for (String pkg : packages) { 1153 if (curInteractor != null && pkg.equals(curInteractor.getPackageName())) { 1154 hit = true; 1155 break; 1156 } else if (curRecognizer != null 1157 && pkg.equals(curRecognizer.getPackageName())) { 1158 hit = true; 1159 break; 1160 } 1161 } 1162 if (hit && doit) { 1163 // The user is force stopping our current interactor/recognizer. 1164 // Clear the current settings and restore default state. 1165 synchronized (VoiceInteractionManagerServiceStub.this) { 1166 unloadAllKeyphraseModels(); 1167 if (mImpl != null) { 1168 mImpl.shutdownLocked(); 1169 mImpl = null; 1170 } 1171 setCurInteractor(null, userHandle); 1172 setCurRecognizer(null, userHandle); 1173 resetCurAssistant(userHandle); 1174 initForUser(userHandle); 1175 switchImplementationIfNeededLocked(true); 1176 } 1177 } 1178 return hit; 1179 } 1180 1181 @Override 1182 public void onHandleUserStop(Intent intent, int userHandle) { 1183 } 1184 1185 @Override 1186 public void onSomePackagesChanged() { 1187 int userHandle = getChangingUserId(); 1188 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle); 1189 1190 synchronized (VoiceInteractionManagerServiceStub.this) { 1191 ComponentName curInteractor = getCurInteractor(userHandle); 1192 ComponentName curRecognizer = getCurRecognizer(userHandle); 1193 ComponentName curAssistant = getCurAssistant(userHandle); 1194 if (curRecognizer == null) { 1195 // Could a new recognizer appear when we don't have one pre-installed? 1196 if (anyPackagesAppearing()) { 1197 curRecognizer = findAvailRecognizer(null, userHandle); 1198 if (curRecognizer != null) { 1199 setCurRecognizer(curRecognizer, userHandle); 1200 } 1201 } 1202 return; 1203 } 1204 1205 if (curInteractor != null) { 1206 int change = isPackageDisappearing(curInteractor.getPackageName()); 1207 if (change == PACKAGE_PERMANENT_CHANGE) { 1208 // The currently set interactor is permanently gone; fall back to 1209 // the default config. 1210 setCurInteractor(null, userHandle); 1211 setCurRecognizer(null, userHandle); 1212 resetCurAssistant(userHandle); 1213 initForUser(userHandle); 1214 return; 1215 } 1216 1217 change = isPackageAppearing(curInteractor.getPackageName()); 1218 if (change != PACKAGE_UNCHANGED) { 1219 // If current interactor is now appearing, for any reason, then 1220 // restart our connection with it. 1221 if (mImpl != null && curInteractor.getPackageName().equals( 1222 mImpl.mComponent.getPackageName())) { 1223 switchImplementationIfNeededLocked(true); 1224 } 1225 } 1226 return; 1227 } 1228 1229 if (curAssistant != null) { 1230 int change = isPackageDisappearing(curAssistant.getPackageName()); 1231 if (change == PACKAGE_PERMANENT_CHANGE) { 1232 // If the currently set assistant is being removed, then we should 1233 // reset back to the default state (which is probably that we prefer 1234 // to have the default full voice interactor enabled). 1235 setCurInteractor(null, userHandle); 1236 setCurRecognizer(null, userHandle); 1237 resetCurAssistant(userHandle); 1238 initForUser(userHandle); 1239 return; 1240 } 1241 } 1242 1243 // There is no interactor, so just deal with a simple recognizer. 1244 int change = isPackageDisappearing(curRecognizer.getPackageName()); 1245 if (change == PACKAGE_PERMANENT_CHANGE 1246 || change == PACKAGE_TEMPORARY_CHANGE) { 1247 setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle); 1248 1249 } else if (isPackageModified(curRecognizer.getPackageName())) { 1250 setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(), 1251 userHandle), userHandle); 1252 } 1253 } 1254 } 1255 }; 1256 } 1257} 1258