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