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