VoiceInteractionManagerService.java revision ae6688b09649447e57468b3e7935691bc09ec9b9
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.ResolveInfo; 30import android.content.pm.ServiceInfo; 31import android.database.ContentObserver; 32import android.hardware.soundtrigger.IRecognitionStatusCallback; 33import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; 34import android.hardware.soundtrigger.SoundTrigger.ModuleProperties; 35import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; 36import android.os.Binder; 37import android.os.Bundle; 38import android.os.Handler; 39import android.os.IBinder; 40import android.os.Parcel; 41import android.os.RemoteException; 42import android.os.UserHandle; 43import android.provider.Settings; 44import android.service.voice.IVoiceInteractionService; 45import android.service.voice.IVoiceInteractionSession; 46import android.service.voice.VoiceInteractionService; 47import android.service.voice.VoiceInteractionServiceInfo; 48import android.speech.RecognitionService; 49import android.text.TextUtils; 50import android.util.Slog; 51 52import com.android.internal.app.IVoiceInteractionManagerService; 53import com.android.internal.app.IVoiceInteractor; 54import com.android.internal.content.PackageMonitor; 55import com.android.internal.os.BackgroundThread; 56import com.android.server.SystemService; 57import com.android.server.UiThread; 58 59import java.io.FileDescriptor; 60import java.io.PrintWriter; 61import java.util.List; 62 63/** 64 * SystemService that publishes an IVoiceInteractionManagerService. 65 */ 66public class VoiceInteractionManagerService extends SystemService { 67 static final String TAG = "VoiceInteractionManagerService"; 68 static final boolean DEBUG = false; 69 70 final Context mContext; 71 final ContentResolver mResolver; 72 final DatabaseHelper mDbHelper; 73 final SoundTriggerHelper mSoundTriggerHelper; 74 75 public VoiceInteractionManagerService(Context context) { 76 super(context); 77 mContext = context; 78 mResolver = context.getContentResolver(); 79 mDbHelper = new DatabaseHelper(context); 80 mSoundTriggerHelper = new SoundTriggerHelper(context); 81 } 82 83 @Override 84 public void onStart() { 85 publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub); 86 } 87 88 @Override 89 public void onBootPhase(int phase) { 90 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { 91 mServiceStub.systemRunning(isSafeMode()); 92 } 93 } 94 95 @Override 96 public void onStartUser(int userHandle) { 97 mServiceStub.initForUser(userHandle); 98 } 99 100 @Override 101 public void onSwitchUser(int userHandle) { 102 mServiceStub.switchUser(userHandle); 103 } 104 105 // implementation entry point and binder service 106 private final VoiceInteractionManagerServiceStub mServiceStub 107 = new VoiceInteractionManagerServiceStub(); 108 109 class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub { 110 111 VoiceInteractionManagerServiceImpl mImpl; 112 113 private boolean mSafeMode; 114 private int mCurUser; 115 116 @Override 117 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 118 throws RemoteException { 119 try { 120 return super.onTransact(code, data, reply, flags); 121 } catch (RuntimeException e) { 122 // The activity manager only throws security exceptions, so let's 123 // log all others. 124 if (!(e instanceof SecurityException)) { 125 Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e); 126 } 127 throw e; 128 } 129 } 130 131 public void initForUser(int userHandle) { 132 if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle); 133 String curInteractorStr = Settings.Secure.getStringForUser( 134 mContext.getContentResolver(), 135 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle); 136 ComponentName curRecognizer = getCurRecognizer(userHandle); 137 VoiceInteractionServiceInfo curInteractorInfo = null; 138 if (DEBUG) Slog.d(TAG, "curInteractorStr=" + curInteractorStr 139 + " curRecognizer=" + curRecognizer); 140 if (curInteractorStr == null && curRecognizer != null 141 && !ActivityManager.isLowRamDeviceStatic()) { 142 // If there is no interactor setting, that means we are upgrading 143 // from an older platform version. If the current recognizer is not 144 // set or matches the preferred recognizer, then we want to upgrade 145 // the user to have the default voice interaction service enabled. 146 // Note that we don't do this for low-RAM devices, since we aren't 147 // supporting voice interaction services there. 148 curInteractorInfo = findAvailInteractor(userHandle, curRecognizer); 149 if (curInteractorInfo != null) { 150 // Looks good! We'll apply this one. To make it happen, we clear the 151 // recognizer so that we don't think we have anything set and will 152 // re-apply the settings. 153 if (DEBUG) Slog.d(TAG, "No set interactor, found avail: " 154 + curInteractorInfo.getServiceInfo().name); 155 curRecognizer = null; 156 } 157 } 158 159 // If we are on a svelte device, make sure an interactor is not currently 160 // enabled; if it is, turn it off. 161 if (ActivityManager.isLowRamDeviceStatic() && curInteractorStr != null) { 162 if (!TextUtils.isEmpty(curInteractorStr)) { 163 if (DEBUG) Slog.d(TAG, "Svelte device; disabling interactor"); 164 setCurInteractor(null, userHandle); 165 curInteractorStr = ""; 166 } 167 } 168 169 if (curRecognizer != null) { 170 // If we already have at least a recognizer, then we probably want to 171 // leave things as they are... unless something has disappeared. 172 IPackageManager pm = AppGlobals.getPackageManager(); 173 ServiceInfo interactorInfo = null; 174 ServiceInfo recognizerInfo = null; 175 ComponentName curInteractor = !TextUtils.isEmpty(curInteractorStr) 176 ? ComponentName.unflattenFromString(curInteractorStr) : null; 177 try { 178 recognizerInfo = pm.getServiceInfo(curRecognizer, 0, userHandle); 179 if (curInteractor != null) { 180 interactorInfo = pm.getServiceInfo(curInteractor, 0, userHandle); 181 } 182 } catch (RemoteException e) { 183 } 184 // If the apps for the currently set components still exist, then all is okay. 185 if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) { 186 if (DEBUG) Slog.d(TAG, "Current interactor/recognizer okay, done!"); 187 return; 188 } 189 if (DEBUG) Slog.d(TAG, "Bad recognizer (" + recognizerInfo + ") or interactor (" 190 + interactorInfo + ")"); 191 } 192 193 // Initializing settings, look for an interactor first (but only on non-svelte). 194 if (curInteractorInfo == null && !ActivityManager.isLowRamDeviceStatic()) { 195 curInteractorInfo = findAvailInteractor(userHandle, null); 196 } 197 198 if (curInteractorInfo != null) { 199 // Eventually it will be an error to not specify this. 200 setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName, 201 curInteractorInfo.getServiceInfo().name), userHandle); 202 if (curInteractorInfo.getRecognitionService() != null) { 203 setCurRecognizer( 204 new ComponentName(curInteractorInfo.getServiceInfo().packageName, 205 curInteractorInfo.getRecognitionService()), userHandle); 206 return; 207 } 208 } 209 210 // No voice interactor, we'll just set up a simple recognizer. 211 curRecognizer = findAvailRecognizer(null, userHandle); 212 if (curRecognizer != null) { 213 if (curInteractorInfo == null) { 214 setCurInteractor(null, userHandle); 215 } 216 setCurRecognizer(curRecognizer, userHandle); 217 } 218 } 219 220 public void systemRunning(boolean safeMode) { 221 mSafeMode = safeMode; 222 223 mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(), 224 UserHandle.ALL, true); 225 new SettingsObserver(UiThread.getHandler()); 226 227 synchronized (this) { 228 mCurUser = ActivityManager.getCurrentUser(); 229 switchImplementationIfNeededLocked(false); 230 } 231 } 232 233 public void switchUser(int userHandle) { 234 synchronized (this) { 235 mCurUser = userHandle; 236 switchImplementationIfNeededLocked(false); 237 } 238 } 239 240 void switchImplementationIfNeededLocked(boolean force) { 241 if (!mSafeMode) { 242 String curService = Settings.Secure.getStringForUser( 243 mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser); 244 ComponentName serviceComponent = null; 245 if (curService != null && !curService.isEmpty()) { 246 try { 247 serviceComponent = ComponentName.unflattenFromString(curService); 248 } catch (RuntimeException e) { 249 Slog.wtf(TAG, "Bad voice interaction service name " + curService, e); 250 serviceComponent = null; 251 } 252 } 253 if (force || mImpl == null || mImpl.mUser != mCurUser 254 || !mImpl.mComponent.equals(serviceComponent)) { 255 mSoundTriggerHelper.stopAllRecognitions(); 256 if (mImpl != null) { 257 mImpl.shutdownLocked(); 258 } 259 if (serviceComponent != null) { 260 mImpl = new VoiceInteractionManagerServiceImpl(mContext, 261 UiThread.getHandler(), this, mCurUser, serviceComponent); 262 mImpl.startLocked(); 263 } else { 264 mImpl = null; 265 } 266 } 267 } 268 } 269 270 VoiceInteractionServiceInfo findAvailInteractor(int userHandle, ComponentName recognizer) { 271 List<ResolveInfo> available = 272 mContext.getPackageManager().queryIntentServicesAsUser( 273 new Intent(VoiceInteractionService.SERVICE_INTERFACE), 0, userHandle); 274 int numAvailable = available.size(); 275 276 if (numAvailable == 0) { 277 Slog.w(TAG, "no available voice interaction services found for user " + userHandle); 278 return null; 279 } else { 280 // Find first system package. We never want to allow third party services to 281 // be automatically selected, because those require approval of the user. 282 VoiceInteractionServiceInfo foundInfo = null; 283 for (int i=0; i<numAvailable; i++) { 284 ServiceInfo cur = available.get(i).serviceInfo; 285 if ((cur.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { 286 ComponentName comp = new ComponentName(cur.packageName, cur.name); 287 try { 288 VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo( 289 mContext.getPackageManager(), comp, userHandle); 290 if (info.getParseError() == null) { 291 if (recognizer == null || info.getServiceInfo().packageName.equals( 292 recognizer.getPackageName())) { 293 if (foundInfo == null) { 294 foundInfo = info; 295 } else { 296 Slog.w(TAG, "More than one voice interaction service, " 297 + "picking first " 298 + new ComponentName( 299 foundInfo.getServiceInfo().packageName, 300 foundInfo.getServiceInfo().name) 301 + " over " 302 + new ComponentName(cur.packageName, cur.name)); 303 } 304 } 305 } else { 306 Slog.w(TAG, "Bad interaction service " + comp + ": " 307 + info.getParseError()); 308 } 309 } catch (PackageManager.NameNotFoundException e) { 310 Slog.w(TAG, "Failure looking up interaction service " + comp); 311 } catch (RemoteException e) { 312 } 313 } 314 } 315 316 return foundInfo; 317 } 318 } 319 320 ComponentName getCurInteractor(int userHandle) { 321 String curInteractor = Settings.Secure.getStringForUser( 322 mContext.getContentResolver(), 323 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle); 324 if (TextUtils.isEmpty(curInteractor)) { 325 return null; 326 } 327 if (DEBUG) Slog.d(TAG, "getCurInteractor curInteractor=" + curInteractor 328 + " user=" + userHandle); 329 return ComponentName.unflattenFromString(curInteractor); 330 } 331 332 void setCurInteractor(ComponentName comp, int userHandle) { 333 Settings.Secure.putStringForUser(mContext.getContentResolver(), 334 Settings.Secure.VOICE_INTERACTION_SERVICE, 335 comp != null ? comp.flattenToShortString() : "", userHandle); 336 if (DEBUG) Slog.d(TAG, "setCurInteractor comp=" + comp 337 + " user=" + userHandle); 338 } 339 340 ComponentName findAvailRecognizer(String prefPackage, int userHandle) { 341 List<ResolveInfo> available = 342 mContext.getPackageManager().queryIntentServicesAsUser( 343 new Intent(RecognitionService.SERVICE_INTERFACE), 0, userHandle); 344 int numAvailable = available.size(); 345 346 if (numAvailable == 0) { 347 Slog.w(TAG, "no available voice recognition services found for user " + userHandle); 348 return null; 349 } else { 350 if (prefPackage != null) { 351 for (int i=0; i<numAvailable; i++) { 352 ServiceInfo serviceInfo = available.get(i).serviceInfo; 353 if (prefPackage.equals(serviceInfo.packageName)) { 354 return new ComponentName(serviceInfo.packageName, serviceInfo.name); 355 } 356 } 357 } 358 if (numAvailable > 1) { 359 Slog.w(TAG, "more than one voice recognition service found, picking first"); 360 } 361 362 ServiceInfo serviceInfo = available.get(0).serviceInfo; 363 return new ComponentName(serviceInfo.packageName, serviceInfo.name); 364 } 365 } 366 367 ComponentName getCurRecognizer(int userHandle) { 368 String curRecognizer = Settings.Secure.getStringForUser( 369 mContext.getContentResolver(), 370 Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle); 371 if (TextUtils.isEmpty(curRecognizer)) { 372 return null; 373 } 374 if (DEBUG) Slog.d(TAG, "getCurRecognizer curRecognizer=" + curRecognizer 375 + " user=" + userHandle); 376 return ComponentName.unflattenFromString(curRecognizer); 377 } 378 379 void setCurRecognizer(ComponentName comp, int userHandle) { 380 Settings.Secure.putStringForUser(mContext.getContentResolver(), 381 Settings.Secure.VOICE_RECOGNITION_SERVICE, 382 comp != null ? comp.flattenToShortString() : "", userHandle); 383 if (DEBUG) Slog.d(TAG, "setCurRecognizer comp=" + comp 384 + " user=" + userHandle); 385 } 386 387 @Override 388 public void startSession(IVoiceInteractionService service, Bundle args, int flags) { 389 synchronized (this) { 390 if (mImpl == null || mImpl.mService == null 391 || service.asBinder() != mImpl.mService.asBinder()) { 392 throw new SecurityException( 393 "Caller is not the current voice interaction service"); 394 } 395 final int callingPid = Binder.getCallingPid(); 396 final int callingUid = Binder.getCallingUid(); 397 final long caller = Binder.clearCallingIdentity(); 398 try { 399 mImpl.startSessionLocked(callingPid, callingUid, args, flags); 400 } finally { 401 Binder.restoreCallingIdentity(caller); 402 } 403 } 404 } 405 406 @Override 407 public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session, 408 IVoiceInteractor interactor) { 409 synchronized (this) { 410 if (mImpl == null) { 411 throw new SecurityException( 412 "deliverNewSession without running voice interaction service"); 413 } 414 final int callingPid = Binder.getCallingPid(); 415 final int callingUid = Binder.getCallingUid(); 416 final long caller = Binder.clearCallingIdentity(); 417 try { 418 return mImpl.deliverNewSessionLocked(callingPid, callingUid, token, session, 419 interactor); 420 } finally { 421 Binder.restoreCallingIdentity(caller); 422 } 423 } 424 } 425 426 @Override 427 public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) { 428 synchronized (this) { 429 if (mImpl == null) { 430 Slog.w(TAG, "startVoiceActivity without running voice interaction service"); 431 return ActivityManager.START_CANCELED; 432 } 433 final int callingPid = Binder.getCallingPid(); 434 final int callingUid = Binder.getCallingUid(); 435 final long caller = Binder.clearCallingIdentity(); 436 try { 437 return mImpl.startVoiceActivityLocked(callingPid, callingUid, token, 438 intent, resolvedType); 439 } finally { 440 Binder.restoreCallingIdentity(caller); 441 } 442 } 443 } 444 445 @Override 446 public void finish(IBinder token) { 447 synchronized (this) { 448 if (mImpl == null) { 449 Slog.w(TAG, "finish without running voice interaction service"); 450 return; 451 } 452 final int callingPid = Binder.getCallingPid(); 453 final int callingUid = Binder.getCallingUid(); 454 final long caller = Binder.clearCallingIdentity(); 455 try { 456 mImpl.finishLocked(callingPid, callingUid, token); 457 } finally { 458 Binder.restoreCallingIdentity(caller); 459 } 460 } 461 } 462 463 //----------------- Model management APIs --------------------------------// 464 465 @Override 466 public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 467 synchronized (this) { 468 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 469 != PackageManager.PERMISSION_GRANTED) { 470 throw new SecurityException("Caller does not hold the permission " 471 + Manifest.permission.MANAGE_VOICE_KEYPHRASES); 472 } 473 } 474 475 if (bcp47Locale == null) { 476 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel"); 477 } 478 479 final int callingUid = UserHandle.getCallingUserId(); 480 final long caller = Binder.clearCallingIdentity(); 481 try { 482 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 483 } finally { 484 Binder.restoreCallingIdentity(caller); 485 } 486 } 487 488 @Override 489 public int updateKeyphraseSoundModel(KeyphraseSoundModel model) { 490 synchronized (this) { 491 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 492 != PackageManager.PERMISSION_GRANTED) { 493 throw new SecurityException("Caller does not hold the permission " 494 + Manifest.permission.MANAGE_VOICE_KEYPHRASES); 495 } 496 if (model == null) { 497 throw new IllegalArgumentException("Model must not be null"); 498 } 499 } 500 501 final long caller = Binder.clearCallingIdentity(); 502 try { 503 if (mDbHelper.updateKeyphraseSoundModel(model)) { 504 synchronized (this) { 505 // Notify the voice interaction service of a change in sound models. 506 if (mImpl != null && mImpl.mService != null) { 507 mImpl.notifySoundModelsChangedLocked(); 508 } 509 } 510 return SoundTriggerHelper.STATUS_OK; 511 } else { 512 return SoundTriggerHelper.STATUS_ERROR; 513 } 514 } finally { 515 Binder.restoreCallingIdentity(caller); 516 } 517 } 518 519 @Override 520 public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 521 synchronized (this) { 522 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 523 != PackageManager.PERMISSION_GRANTED) { 524 throw new SecurityException("Caller does not hold the permission " 525 + Manifest.permission.MANAGE_VOICE_KEYPHRASES); 526 } 527 } 528 529 if (bcp47Locale == null) { 530 throw new IllegalArgumentException( 531 "Illegal argument(s) in deleteKeyphraseSoundModel"); 532 } 533 534 final int callingUid = UserHandle.getCallingUserId(); 535 final long caller = Binder.clearCallingIdentity(); 536 boolean deleted = false; 537 try { 538 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 539 return deleted ? SoundTriggerHelper.STATUS_OK : SoundTriggerHelper.STATUS_ERROR; 540 } finally { 541 if (deleted) { 542 synchronized (this) { 543 // Notify the voice interaction service of a change in sound models. 544 if (mImpl != null && mImpl.mService != null) { 545 mImpl.notifySoundModelsChangedLocked(); 546 } 547 } 548 } 549 Binder.restoreCallingIdentity(caller); 550 } 551 } 552 553 //----------------- SoundTrigger APIs --------------------------------// 554 @Override 555 public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId, 556 String bcp47Locale) { 557 synchronized (this) { 558 if (mImpl == null || mImpl.mService == null 559 || service.asBinder() != mImpl.mService.asBinder()) { 560 throw new SecurityException( 561 "Caller is not the current voice interaction service"); 562 } 563 } 564 565 if (bcp47Locale == null) { 566 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase"); 567 } 568 569 final int callingUid = UserHandle.getCallingUserId(); 570 final long caller = Binder.clearCallingIdentity(); 571 try { 572 KeyphraseSoundModel model = 573 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 574 return model != null; 575 } finally { 576 Binder.restoreCallingIdentity(caller); 577 } 578 } 579 580 @Override 581 public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) { 582 // Allow the call if this is the current voice interaction service. 583 synchronized (this) { 584 if (mImpl == null || mImpl.mService == null 585 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 586 throw new SecurityException( 587 "Caller is not the current voice interaction service"); 588 } 589 590 final long caller = Binder.clearCallingIdentity(); 591 try { 592 return mSoundTriggerHelper.moduleProperties; 593 } finally { 594 Binder.restoreCallingIdentity(caller); 595 } 596 } 597 } 598 599 @Override 600 public int startRecognition(IVoiceInteractionService service, int keyphraseId, 601 String bcp47Locale, IRecognitionStatusCallback callback, 602 RecognitionConfig recognitionConfig) { 603 // Allow the call if this is the current voice interaction service. 604 synchronized (this) { 605 if (mImpl == null || mImpl.mService == null 606 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 607 throw new SecurityException( 608 "Caller is not the current voice interaction service"); 609 } 610 611 if (callback == null || recognitionConfig == null || bcp47Locale == null) { 612 throw new IllegalArgumentException("Illegal argument(s) in startRecognition"); 613 } 614 } 615 616 int callingUid = UserHandle.getCallingUserId(); 617 final long caller = Binder.clearCallingIdentity(); 618 try { 619 KeyphraseSoundModel soundModel = 620 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 621 if (soundModel == null 622 || soundModel.uuid == null 623 || soundModel.keyphrases == null) { 624 Slog.w(TAG, "No matching sound model found in startRecognition"); 625 return SoundTriggerHelper.STATUS_ERROR; 626 } else { 627 return mSoundTriggerHelper.startRecognition( 628 keyphraseId, soundModel, callback, recognitionConfig); 629 } 630 } finally { 631 Binder.restoreCallingIdentity(caller); 632 } 633 } 634 635 @Override 636 public int stopRecognition(IVoiceInteractionService service, int keyphraseId, 637 IRecognitionStatusCallback callback) { 638 // Allow the call if this is the current voice interaction service. 639 synchronized (this) { 640 if (mImpl == null || mImpl.mService == null 641 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 642 throw new SecurityException( 643 "Caller is not the current voice interaction service"); 644 } 645 } 646 647 final long caller = Binder.clearCallingIdentity(); 648 try { 649 return mSoundTriggerHelper.stopRecognition(keyphraseId, callback); 650 } finally { 651 Binder.restoreCallingIdentity(caller); 652 } 653 } 654 655 @Override 656 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 657 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 658 != PackageManager.PERMISSION_GRANTED) { 659 pw.println("Permission Denial: can't dump PowerManager from from pid=" 660 + Binder.getCallingPid() 661 + ", uid=" + Binder.getCallingUid()); 662 return; 663 } 664 synchronized (this) { 665 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n"); 666 if (mImpl == null) { 667 pw.println(" (No active implementation)"); 668 return; 669 } 670 mImpl.dumpLocked(fd, pw, args); 671 } 672 mSoundTriggerHelper.dump(fd, pw, args); 673 } 674 675 class SettingsObserver extends ContentObserver { 676 SettingsObserver(Handler handler) { 677 super(handler); 678 ContentResolver resolver = mContext.getContentResolver(); 679 resolver.registerContentObserver(Settings.Secure.getUriFor( 680 Settings.Secure.VOICE_INTERACTION_SERVICE), false, this); 681 } 682 683 @Override public void onChange(boolean selfChange) { 684 synchronized (VoiceInteractionManagerServiceStub.this) { 685 switchImplementationIfNeededLocked(false); 686 } 687 } 688 } 689 690 PackageMonitor mPackageMonitor = new PackageMonitor() { 691 @Override 692 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 693 return super.onHandleForceStop(intent, packages, uid, doit); 694 } 695 696 @Override 697 public void onHandleUserStop(Intent intent, int userHandle) { 698 } 699 700 @Override 701 public void onSomePackagesChanged() { 702 int userHandle = getChangingUserId(); 703 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle); 704 705 ComponentName curInteractor = getCurInteractor(userHandle); 706 ComponentName curRecognizer = getCurRecognizer(userHandle); 707 if (curRecognizer == null) { 708 // Could a new recognizer appear when we don't have one pre-installed? 709 if (anyPackagesAppearing()) { 710 curRecognizer = findAvailRecognizer(null, userHandle); 711 if (curRecognizer != null) { 712 setCurRecognizer(curRecognizer, userHandle); 713 } 714 } 715 return; 716 } 717 718 if (curInteractor != null) { 719 int change = isPackageDisappearing(curInteractor.getPackageName()); 720 if (change == PACKAGE_PERMANENT_CHANGE) { 721 // The currently set interactor is permanently gone; fall back to 722 // the default config. 723 setCurInteractor(null, userHandle); 724 setCurRecognizer(null, userHandle); 725 initForUser(userHandle); 726 return; 727 } 728 729 change = isPackageAppearing(curInteractor.getPackageName()); 730 if (change != PACKAGE_UNCHANGED) { 731 // If current interactor is now appearing, for any reason, then 732 // restart our connection with it. 733 if (mImpl != null && curInteractor.getPackageName().equals( 734 mImpl.mComponent.getPackageName())) { 735 switchImplementationIfNeededLocked(true); 736 } 737 } 738 return; 739 } 740 741 // There is no interactor, so just deal with a simple recognizer. 742 int change = isPackageDisappearing(curRecognizer.getPackageName()); 743 if (change == PACKAGE_PERMANENT_CHANGE 744 || change == PACKAGE_TEMPORARY_CHANGE) { 745 setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle); 746 747 } else if (isPackageModified(curRecognizer.getPackageName())) { 748 setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(), 749 userHandle), userHandle); 750 } 751 } 752 }; 753 } 754} 755