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