VoiceInteractionManagerService.java revision cc3a46ada84b2c27544df0fa3369631c8dc9386e
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 /* showCallback */); 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 int callingPid = Binder.getCallingPid(); 467 final int callingUid = Binder.getCallingUid(); 468 final long caller = Binder.clearCallingIdentity(); 469 try { 470 return mImpl.deliverNewSessionLocked(callingPid, callingUid, token, session, 471 interactor); 472 } finally { 473 Binder.restoreCallingIdentity(caller); 474 } 475 } 476 } 477 478 @Override 479 public boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) { 480 synchronized (this) { 481 if (mImpl == null) { 482 Slog.w(TAG, "showSessionFromSession without running voice interaction service"); 483 return false; 484 } 485 final long caller = Binder.clearCallingIdentity(); 486 try { 487 return mImpl.showSessionLocked(sessionArgs, flags, null /* showCallback */); 488 } finally { 489 Binder.restoreCallingIdentity(caller); 490 } 491 } 492 } 493 494 @Override 495 public boolean hideSessionFromSession(IBinder token) { 496 synchronized (this) { 497 if (mImpl == null) { 498 Slog.w(TAG, "hideSessionFromSession without running voice interaction service"); 499 return false; 500 } 501 final long caller = Binder.clearCallingIdentity(); 502 try { 503 return mImpl.hideSessionLocked(); 504 } finally { 505 Binder.restoreCallingIdentity(caller); 506 } 507 } 508 } 509 510 @Override 511 public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) { 512 synchronized (this) { 513 if (mImpl == null) { 514 Slog.w(TAG, "startVoiceActivity without running voice interaction service"); 515 return ActivityManager.START_CANCELED; 516 } 517 final int callingPid = Binder.getCallingPid(); 518 final int callingUid = Binder.getCallingUid(); 519 final long caller = Binder.clearCallingIdentity(); 520 try { 521 return mImpl.startVoiceActivityLocked(callingPid, callingUid, token, 522 intent, resolvedType); 523 } finally { 524 Binder.restoreCallingIdentity(caller); 525 } 526 } 527 } 528 529 @Override 530 public void setKeepAwake(IBinder token, boolean keepAwake) { 531 synchronized (this) { 532 if (mImpl == null) { 533 Slog.w(TAG, "setKeepAwake without running voice interaction service"); 534 return; 535 } 536 final int callingPid = Binder.getCallingPid(); 537 final int callingUid = Binder.getCallingUid(); 538 final long caller = Binder.clearCallingIdentity(); 539 try { 540 mImpl.setKeepAwakeLocked(callingPid, callingUid, token, keepAwake); 541 } finally { 542 Binder.restoreCallingIdentity(caller); 543 } 544 } 545 } 546 547 @Override 548 public void finish(IBinder token) { 549 synchronized (this) { 550 if (mImpl == null) { 551 Slog.w(TAG, "finish without running voice interaction service"); 552 return; 553 } 554 final long caller = Binder.clearCallingIdentity(); 555 try { 556 mImpl.finishLocked(token); 557 } finally { 558 Binder.restoreCallingIdentity(caller); 559 } 560 } 561 } 562 563 //----------------- Model management APIs --------------------------------// 564 565 @Override 566 public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 567 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); 568 569 if (bcp47Locale == null) { 570 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel"); 571 } 572 573 final int callingUid = UserHandle.getCallingUserId(); 574 final long caller = Binder.clearCallingIdentity(); 575 try { 576 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 577 } finally { 578 Binder.restoreCallingIdentity(caller); 579 } 580 } 581 582 @Override 583 public int updateKeyphraseSoundModel(KeyphraseSoundModel model) { 584 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); 585 if (model == null) { 586 throw new IllegalArgumentException("Model must not be null"); 587 } 588 589 final long caller = Binder.clearCallingIdentity(); 590 try { 591 if (mDbHelper.updateKeyphraseSoundModel(model)) { 592 synchronized (this) { 593 // Notify the voice interaction service of a change in sound models. 594 if (mImpl != null && mImpl.mService != null) { 595 mImpl.notifySoundModelsChangedLocked(); 596 } 597 } 598 return SoundTriggerHelper.STATUS_OK; 599 } else { 600 return SoundTriggerHelper.STATUS_ERROR; 601 } 602 } finally { 603 Binder.restoreCallingIdentity(caller); 604 } 605 } 606 607 @Override 608 public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 609 enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES); 610 611 if (bcp47Locale == null) { 612 throw new IllegalArgumentException( 613 "Illegal argument(s) in deleteKeyphraseSoundModel"); 614 } 615 616 final int callingUid = UserHandle.getCallingUserId(); 617 final long caller = Binder.clearCallingIdentity(); 618 boolean deleted = false; 619 try { 620 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 621 return deleted ? SoundTriggerHelper.STATUS_OK : SoundTriggerHelper.STATUS_ERROR; 622 } finally { 623 if (deleted) { 624 synchronized (this) { 625 // Notify the voice interaction service of a change in sound models. 626 if (mImpl != null && mImpl.mService != null) { 627 mImpl.notifySoundModelsChangedLocked(); 628 } 629 } 630 } 631 Binder.restoreCallingIdentity(caller); 632 } 633 } 634 635 //----------------- SoundTrigger APIs --------------------------------// 636 @Override 637 public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId, 638 String bcp47Locale) { 639 synchronized (this) { 640 if (mImpl == null || mImpl.mService == null 641 || service.asBinder() != mImpl.mService.asBinder()) { 642 throw new SecurityException( 643 "Caller is not the current voice interaction service"); 644 } 645 } 646 647 if (bcp47Locale == null) { 648 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase"); 649 } 650 651 final int callingUid = UserHandle.getCallingUserId(); 652 final long caller = Binder.clearCallingIdentity(); 653 try { 654 KeyphraseSoundModel model = 655 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 656 return model != null; 657 } finally { 658 Binder.restoreCallingIdentity(caller); 659 } 660 } 661 662 @Override 663 public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) { 664 // Allow the call if this is the current voice interaction service. 665 synchronized (this) { 666 if (mImpl == null || mImpl.mService == null 667 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 668 throw new SecurityException( 669 "Caller is not the current voice interaction service"); 670 } 671 672 final long caller = Binder.clearCallingIdentity(); 673 try { 674 return mSoundTriggerHelper.moduleProperties; 675 } finally { 676 Binder.restoreCallingIdentity(caller); 677 } 678 } 679 } 680 681 @Override 682 public int startRecognition(IVoiceInteractionService service, int keyphraseId, 683 String bcp47Locale, IRecognitionStatusCallback callback, 684 RecognitionConfig recognitionConfig) { 685 // Allow the call if this is the current voice interaction service. 686 synchronized (this) { 687 if (mImpl == null || mImpl.mService == null 688 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 689 throw new SecurityException( 690 "Caller is not the current voice interaction service"); 691 } 692 693 if (callback == null || recognitionConfig == null || bcp47Locale == null) { 694 throw new IllegalArgumentException("Illegal argument(s) in startRecognition"); 695 } 696 } 697 698 int callingUid = UserHandle.getCallingUserId(); 699 final long caller = Binder.clearCallingIdentity(); 700 try { 701 KeyphraseSoundModel soundModel = 702 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 703 if (soundModel == null 704 || soundModel.uuid == null 705 || soundModel.keyphrases == null) { 706 Slog.w(TAG, "No matching sound model found in startRecognition"); 707 return SoundTriggerHelper.STATUS_ERROR; 708 } else { 709 return mSoundTriggerHelper.startRecognition( 710 keyphraseId, soundModel, callback, recognitionConfig); 711 } 712 } finally { 713 Binder.restoreCallingIdentity(caller); 714 } 715 } 716 717 @Override 718 public int stopRecognition(IVoiceInteractionService service, int keyphraseId, 719 IRecognitionStatusCallback callback) { 720 // Allow the call if this is the current voice interaction service. 721 synchronized (this) { 722 if (mImpl == null || mImpl.mService == null 723 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 724 throw new SecurityException( 725 "Caller is not the current voice interaction service"); 726 } 727 } 728 729 final long caller = Binder.clearCallingIdentity(); 730 try { 731 return mSoundTriggerHelper.stopRecognition(keyphraseId, callback); 732 } finally { 733 Binder.restoreCallingIdentity(caller); 734 } 735 } 736 737 @Override 738 public ComponentName getActiveServiceComponentName() { 739 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 740 synchronized (this) { 741 return mImpl != null ? mImpl.mComponent : null; 742 } 743 } 744 745 @Override 746 public void showSessionForActiveService(IVoiceInteractionSessionShowCallback showCallback) { 747 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 748 synchronized (this) { 749 if (mImpl == null) { 750 Slog.w(TAG, "showSessionForActiveService without running voice interaction" 751 + "service"); 752 return; 753 } 754 final long caller = Binder.clearCallingIdentity(); 755 try { 756 mImpl.showSessionLocked(new Bundle() /* sessionArgs */, 757 VoiceInteractionSession.SHOW_SOURCE_ASSIST_GESTURE 758 | VoiceInteractionSession.SHOW_WITH_ASSIST 759 | VoiceInteractionSession.SHOW_WITH_SCREENSHOT, 760 showCallback); 761 } finally { 762 Binder.restoreCallingIdentity(caller); 763 } 764 } 765 } 766 767 @Override 768 public void hideCurrentSession() throws RemoteException { 769 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 770 synchronized (this) { 771 if (mImpl == null) { 772 return; 773 } 774 final long caller = Binder.clearCallingIdentity(); 775 try { 776 if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) { 777 try { 778 mImpl.mActiveSession.mSession.closeSystemDialogs(); 779 } catch (RemoteException e) { 780 Log.w(TAG, "Failed to call closeSystemDialogs", e); 781 } 782 } 783 } finally { 784 Binder.restoreCallingIdentity(caller); 785 } 786 } 787 } 788 789 @Override 790 public void launchVoiceAssistFromKeyguard() { 791 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 792 synchronized (this) { 793 if (mImpl == null) { 794 Slog.w(TAG, "launchVoiceAssistFromKeyguard without running voice interaction" 795 + "service"); 796 return; 797 } 798 final long caller = Binder.clearCallingIdentity(); 799 try { 800 mImpl.launchVoiceAssistFromKeyguard(); 801 } finally { 802 Binder.restoreCallingIdentity(caller); 803 } 804 } 805 } 806 807 @Override 808 public boolean isSessionRunning() { 809 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 810 synchronized (this) { 811 return mImpl != null && mImpl.mActiveSession != null; 812 } 813 } 814 815 @Override 816 public boolean activeServiceSupportsAssist() { 817 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 818 synchronized (this) { 819 return mImpl != null && mImpl.mInfo != null && mImpl.mInfo.getSupportsAssist(); 820 } 821 } 822 823 @Override 824 public boolean activeServiceSupportsLaunchFromKeyguard() throws RemoteException { 825 enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE); 826 synchronized (this) { 827 return mImpl != null && mImpl.mInfo != null 828 && mImpl.mInfo.getSupportsLaunchFromKeyguard(); 829 } 830 } 831 832 @Override 833 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 834 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 835 != PackageManager.PERMISSION_GRANTED) { 836 pw.println("Permission Denial: can't dump PowerManager from from pid=" 837 + Binder.getCallingPid() 838 + ", uid=" + Binder.getCallingUid()); 839 return; 840 } 841 synchronized (this) { 842 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n"); 843 pw.println(" mEnableService: " + mEnableService); 844 if (mImpl == null) { 845 pw.println(" (No active implementation)"); 846 return; 847 } 848 mImpl.dumpLocked(fd, pw, args); 849 } 850 mSoundTriggerHelper.dump(fd, pw, args); 851 } 852 853 private void enforceCallingPermission(String permission) { 854 if (mContext.checkCallingPermission(permission) != PackageManager.PERMISSION_GRANTED) { 855 throw new SecurityException("Caller does not hold the permission " + permission); 856 } 857 } 858 859 class SettingsObserver extends ContentObserver { 860 SettingsObserver(Handler handler) { 861 super(handler); 862 ContentResolver resolver = mContext.getContentResolver(); 863 resolver.registerContentObserver(Settings.Secure.getUriFor( 864 Settings.Secure.VOICE_INTERACTION_SERVICE), false, this, 865 UserHandle.USER_ALL); 866 } 867 868 @Override public void onChange(boolean selfChange) { 869 synchronized (VoiceInteractionManagerServiceStub.this) { 870 switchImplementationIfNeededLocked(false); 871 } 872 } 873 } 874 875 PackageMonitor mPackageMonitor = new PackageMonitor() { 876 @Override 877 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 878 if (DEBUG) Slog.d(TAG, "onHandleForceStop uid=" + uid + " doit=" + doit); 879 880 int userHandle = UserHandle.getUserId(uid); 881 ComponentName curInteractor = getCurInteractor(userHandle); 882 ComponentName curRecognizer = getCurRecognizer(userHandle); 883 boolean hit = false; 884 for (String pkg : packages) { 885 if (curInteractor != null && pkg.equals(curInteractor.getPackageName())) { 886 hit = true; 887 break; 888 } else if (curRecognizer != null 889 && pkg.equals(curRecognizer.getPackageName())) { 890 hit = true; 891 break; 892 } 893 } 894 if (hit && doit) { 895 // The user is force stopping our current interactor/recognizer. 896 // Clear the current settings and restore default state. 897 synchronized (VoiceInteractionManagerService.this) { 898 mSoundTriggerHelper.stopAllRecognitions(); 899 if (mImpl != null) { 900 mImpl.shutdownLocked(); 901 mImpl = null; 902 } 903 setCurInteractor(null, userHandle); 904 setCurRecognizer(null, userHandle); 905 resetCurAssistant(userHandle); 906 initForUser(userHandle); 907 switchImplementationIfNeededLocked(true); 908 } 909 } 910 return hit; 911 } 912 913 @Override 914 public void onHandleUserStop(Intent intent, int userHandle) { 915 } 916 917 @Override 918 public void onSomePackagesChanged() { 919 int userHandle = getChangingUserId(); 920 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle); 921 922 synchronized (VoiceInteractionManagerService.this) { 923 ComponentName curInteractor = getCurInteractor(userHandle); 924 ComponentName curRecognizer = getCurRecognizer(userHandle); 925 if (curRecognizer == null) { 926 // Could a new recognizer appear when we don't have one pre-installed? 927 if (anyPackagesAppearing()) { 928 curRecognizer = findAvailRecognizer(null, userHandle); 929 if (curRecognizer != null) { 930 setCurRecognizer(curRecognizer, userHandle); 931 } 932 } 933 return; 934 } 935 936 if (curInteractor != null) { 937 int change = isPackageDisappearing(curInteractor.getPackageName()); 938 if (change == PACKAGE_PERMANENT_CHANGE) { 939 // The currently set interactor is permanently gone; fall back to 940 // the default config. 941 setCurInteractor(null, userHandle); 942 setCurRecognizer(null, userHandle); 943 initForUser(userHandle); 944 return; 945 } 946 947 change = isPackageAppearing(curInteractor.getPackageName()); 948 if (change != PACKAGE_UNCHANGED) { 949 // If current interactor is now appearing, for any reason, then 950 // restart our connection with it. 951 if (mImpl != null && curInteractor.getPackageName().equals( 952 mImpl.mComponent.getPackageName())) { 953 switchImplementationIfNeededLocked(true); 954 } 955 } 956 return; 957 } 958 959 // There is no interactor, so just deal with a simple recognizer. 960 int change = isPackageDisappearing(curRecognizer.getPackageName()); 961 if (change == PACKAGE_PERMANENT_CHANGE 962 || change == PACKAGE_TEMPORARY_CHANGE) { 963 setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle); 964 965 } else if (isPackageModified(curRecognizer.getPackageName())) { 966 setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(), 967 userHandle), userHandle); 968 } 969 } 970 } 971 }; 972 } 973} 974