VoiceInteractionManagerService.java revision ffeecb1bfb9b71f4b62c9ef1fbf7b58a7a63f655
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 showSession(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.showSessionLocked(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 boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) { 428 synchronized (this) { 429 if (mImpl == null) { 430 Slog.w(TAG, "showSessionFromSession without running voice interaction service"); 431 return false; 432 } 433 final int callingPid = Binder.getCallingPid(); 434 final int callingUid = Binder.getCallingUid(); 435 final long caller = Binder.clearCallingIdentity(); 436 try { 437 return mImpl.showSessionLocked(callingPid, callingUid, sessionArgs, flags); 438 } finally { 439 Binder.restoreCallingIdentity(caller); 440 } 441 } 442 } 443 444 @Override 445 public boolean hideSessionFromSession(IBinder token) { 446 synchronized (this) { 447 if (mImpl == null) { 448 Slog.w(TAG, "hideSessionFromSession without running voice interaction service"); 449 return false; 450 } 451 final int callingPid = Binder.getCallingPid(); 452 final int callingUid = Binder.getCallingUid(); 453 final long caller = Binder.clearCallingIdentity(); 454 try { 455 return mImpl.hideSessionLocked(callingPid, callingUid); 456 } finally { 457 Binder.restoreCallingIdentity(caller); 458 } 459 } 460 } 461 462 @Override 463 public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) { 464 synchronized (this) { 465 if (mImpl == null) { 466 Slog.w(TAG, "startVoiceActivity without running voice interaction service"); 467 return ActivityManager.START_CANCELED; 468 } 469 final int callingPid = Binder.getCallingPid(); 470 final int callingUid = Binder.getCallingUid(); 471 final long caller = Binder.clearCallingIdentity(); 472 try { 473 return mImpl.startVoiceActivityLocked(callingPid, callingUid, token, 474 intent, resolvedType); 475 } finally { 476 Binder.restoreCallingIdentity(caller); 477 } 478 } 479 } 480 481 @Override 482 public void finish(IBinder token) { 483 synchronized (this) { 484 if (mImpl == null) { 485 Slog.w(TAG, "finish without running voice interaction service"); 486 return; 487 } 488 final int callingPid = Binder.getCallingPid(); 489 final int callingUid = Binder.getCallingUid(); 490 final long caller = Binder.clearCallingIdentity(); 491 try { 492 mImpl.finishLocked(callingPid, callingUid, token); 493 } finally { 494 Binder.restoreCallingIdentity(caller); 495 } 496 } 497 } 498 499 //----------------- Model management APIs --------------------------------// 500 501 @Override 502 public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 503 synchronized (this) { 504 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 505 != PackageManager.PERMISSION_GRANTED) { 506 throw new SecurityException("Caller does not hold the permission " 507 + Manifest.permission.MANAGE_VOICE_KEYPHRASES); 508 } 509 } 510 511 if (bcp47Locale == null) { 512 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel"); 513 } 514 515 final int callingUid = UserHandle.getCallingUserId(); 516 final long caller = Binder.clearCallingIdentity(); 517 try { 518 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 519 } finally { 520 Binder.restoreCallingIdentity(caller); 521 } 522 } 523 524 @Override 525 public int updateKeyphraseSoundModel(KeyphraseSoundModel model) { 526 synchronized (this) { 527 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 528 != PackageManager.PERMISSION_GRANTED) { 529 throw new SecurityException("Caller does not hold the permission " 530 + Manifest.permission.MANAGE_VOICE_KEYPHRASES); 531 } 532 if (model == null) { 533 throw new IllegalArgumentException("Model must not be null"); 534 } 535 } 536 537 final long caller = Binder.clearCallingIdentity(); 538 try { 539 if (mDbHelper.updateKeyphraseSoundModel(model)) { 540 synchronized (this) { 541 // Notify the voice interaction service of a change in sound models. 542 if (mImpl != null && mImpl.mService != null) { 543 mImpl.notifySoundModelsChangedLocked(); 544 } 545 } 546 return SoundTriggerHelper.STATUS_OK; 547 } else { 548 return SoundTriggerHelper.STATUS_ERROR; 549 } 550 } finally { 551 Binder.restoreCallingIdentity(caller); 552 } 553 } 554 555 @Override 556 public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 557 synchronized (this) { 558 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 559 != PackageManager.PERMISSION_GRANTED) { 560 throw new SecurityException("Caller does not hold the permission " 561 + Manifest.permission.MANAGE_VOICE_KEYPHRASES); 562 } 563 } 564 565 if (bcp47Locale == null) { 566 throw new IllegalArgumentException( 567 "Illegal argument(s) in deleteKeyphraseSoundModel"); 568 } 569 570 final int callingUid = UserHandle.getCallingUserId(); 571 final long caller = Binder.clearCallingIdentity(); 572 boolean deleted = false; 573 try { 574 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 575 return deleted ? SoundTriggerHelper.STATUS_OK : SoundTriggerHelper.STATUS_ERROR; 576 } finally { 577 if (deleted) { 578 synchronized (this) { 579 // Notify the voice interaction service of a change in sound models. 580 if (mImpl != null && mImpl.mService != null) { 581 mImpl.notifySoundModelsChangedLocked(); 582 } 583 } 584 } 585 Binder.restoreCallingIdentity(caller); 586 } 587 } 588 589 //----------------- SoundTrigger APIs --------------------------------// 590 @Override 591 public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId, 592 String bcp47Locale) { 593 synchronized (this) { 594 if (mImpl == null || mImpl.mService == null 595 || service.asBinder() != mImpl.mService.asBinder()) { 596 throw new SecurityException( 597 "Caller is not the current voice interaction service"); 598 } 599 } 600 601 if (bcp47Locale == null) { 602 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase"); 603 } 604 605 final int callingUid = UserHandle.getCallingUserId(); 606 final long caller = Binder.clearCallingIdentity(); 607 try { 608 KeyphraseSoundModel model = 609 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 610 return model != null; 611 } finally { 612 Binder.restoreCallingIdentity(caller); 613 } 614 } 615 616 @Override 617 public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) { 618 // Allow the call if this is the current voice interaction service. 619 synchronized (this) { 620 if (mImpl == null || mImpl.mService == null 621 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 622 throw new SecurityException( 623 "Caller is not the current voice interaction service"); 624 } 625 626 final long caller = Binder.clearCallingIdentity(); 627 try { 628 return mSoundTriggerHelper.moduleProperties; 629 } finally { 630 Binder.restoreCallingIdentity(caller); 631 } 632 } 633 } 634 635 @Override 636 public int startRecognition(IVoiceInteractionService service, int keyphraseId, 637 String bcp47Locale, IRecognitionStatusCallback callback, 638 RecognitionConfig recognitionConfig) { 639 // Allow the call if this is the current voice interaction service. 640 synchronized (this) { 641 if (mImpl == null || mImpl.mService == null 642 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 643 throw new SecurityException( 644 "Caller is not the current voice interaction service"); 645 } 646 647 if (callback == null || recognitionConfig == null || bcp47Locale == null) { 648 throw new IllegalArgumentException("Illegal argument(s) in startRecognition"); 649 } 650 } 651 652 int callingUid = UserHandle.getCallingUserId(); 653 final long caller = Binder.clearCallingIdentity(); 654 try { 655 KeyphraseSoundModel soundModel = 656 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 657 if (soundModel == null 658 || soundModel.uuid == null 659 || soundModel.keyphrases == null) { 660 Slog.w(TAG, "No matching sound model found in startRecognition"); 661 return SoundTriggerHelper.STATUS_ERROR; 662 } else { 663 return mSoundTriggerHelper.startRecognition( 664 keyphraseId, soundModel, callback, recognitionConfig); 665 } 666 } finally { 667 Binder.restoreCallingIdentity(caller); 668 } 669 } 670 671 @Override 672 public int stopRecognition(IVoiceInteractionService service, int keyphraseId, 673 IRecognitionStatusCallback callback) { 674 // Allow the call if this is the current voice interaction service. 675 synchronized (this) { 676 if (mImpl == null || mImpl.mService == null 677 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 678 throw new SecurityException( 679 "Caller is not the current voice interaction service"); 680 } 681 } 682 683 final long caller = Binder.clearCallingIdentity(); 684 try { 685 return mSoundTriggerHelper.stopRecognition(keyphraseId, callback); 686 } finally { 687 Binder.restoreCallingIdentity(caller); 688 } 689 } 690 691 @Override 692 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 693 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 694 != PackageManager.PERMISSION_GRANTED) { 695 pw.println("Permission Denial: can't dump PowerManager from from pid=" 696 + Binder.getCallingPid() 697 + ", uid=" + Binder.getCallingUid()); 698 return; 699 } 700 synchronized (this) { 701 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n"); 702 if (mImpl == null) { 703 pw.println(" (No active implementation)"); 704 return; 705 } 706 mImpl.dumpLocked(fd, pw, args); 707 } 708 mSoundTriggerHelper.dump(fd, pw, args); 709 } 710 711 class SettingsObserver extends ContentObserver { 712 SettingsObserver(Handler handler) { 713 super(handler); 714 ContentResolver resolver = mContext.getContentResolver(); 715 resolver.registerContentObserver(Settings.Secure.getUriFor( 716 Settings.Secure.VOICE_INTERACTION_SERVICE), false, this); 717 } 718 719 @Override public void onChange(boolean selfChange) { 720 synchronized (VoiceInteractionManagerServiceStub.this) { 721 switchImplementationIfNeededLocked(false); 722 } 723 } 724 } 725 726 PackageMonitor mPackageMonitor = new PackageMonitor() { 727 @Override 728 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 729 return super.onHandleForceStop(intent, packages, uid, doit); 730 } 731 732 @Override 733 public void onHandleUserStop(Intent intent, int userHandle) { 734 } 735 736 @Override 737 public void onSomePackagesChanged() { 738 int userHandle = getChangingUserId(); 739 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle); 740 741 ComponentName curInteractor = getCurInteractor(userHandle); 742 ComponentName curRecognizer = getCurRecognizer(userHandle); 743 if (curRecognizer == null) { 744 // Could a new recognizer appear when we don't have one pre-installed? 745 if (anyPackagesAppearing()) { 746 curRecognizer = findAvailRecognizer(null, userHandle); 747 if (curRecognizer != null) { 748 setCurRecognizer(curRecognizer, userHandle); 749 } 750 } 751 return; 752 } 753 754 if (curInteractor != null) { 755 int change = isPackageDisappearing(curInteractor.getPackageName()); 756 if (change == PACKAGE_PERMANENT_CHANGE) { 757 // The currently set interactor is permanently gone; fall back to 758 // the default config. 759 setCurInteractor(null, userHandle); 760 setCurRecognizer(null, userHandle); 761 initForUser(userHandle); 762 return; 763 } 764 765 change = isPackageAppearing(curInteractor.getPackageName()); 766 if (change != PACKAGE_UNCHANGED) { 767 // If current interactor is now appearing, for any reason, then 768 // restart our connection with it. 769 if (mImpl != null && curInteractor.getPackageName().equals( 770 mImpl.mComponent.getPackageName())) { 771 switchImplementationIfNeededLocked(true); 772 } 773 } 774 return; 775 } 776 777 // There is no interactor, so just deal with a simple recognizer. 778 int change = isPackageDisappearing(curRecognizer.getPackageName()); 779 if (change == PACKAGE_PERMANENT_CHANGE 780 || change == PACKAGE_TEMPORARY_CHANGE) { 781 setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle); 782 783 } else if (isPackageModified(curRecognizer.getPackageName())) { 784 setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(), 785 userHandle), userHandle); 786 } 787 } 788 }; 789 } 790} 791