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